react-native-acoustic-connect 19.0.11 → 19.0.34

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 (380) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/ConnectConfig.example.json +1 -1
  3. package/README.md +426 -3
  4. package/android/build.gradle +119 -3
  5. package/android/config.gradle +123 -13
  6. package/android/src/main/assets/ConnectAdvancedConfig.json +1 -1
  7. package/android/src/main/assets/EOCoreAdvancedConfig.json +1 -1
  8. package/android/src/main/assets/TealeafAdvancedConfig.json +1 -1
  9. package/android/src/main/java/com/acousticconnectrn/HybridAcousticConnectRN.kt +457 -37
  10. package/app.plugin.js +2 -2
  11. package/ios/AcousticConnectRNConfig.json +2 -2
  12. package/ios/ConnectRNParsing.swift +229 -0
  13. package/ios/HybridAcousticConnectRN.swift +290 -30
  14. package/lib/commonjs/TLTRN.js +116 -3
  15. package/lib/commonjs/TLTRN.js.map +1 -1
  16. package/lib/commonjs/components/Connect.js +145 -27
  17. package/lib/commonjs/components/Connect.js.map +1 -1
  18. package/lib/commonjs/index.js +3 -0
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/module/TLTRN.js +116 -3
  21. package/lib/module/TLTRN.js.map +1 -1
  22. package/lib/module/components/Connect.js +146 -28
  23. package/lib/module/components/Connect.js.map +1 -1
  24. package/lib/module/index.js +5 -0
  25. package/lib/module/index.js.map +1 -1
  26. package/lib/typescript/src/TLTRN.d.ts +85 -1
  27. package/lib/typescript/src/TLTRN.d.ts.map +1 -1
  28. package/lib/typescript/src/components/Connect.d.ts.map +1 -1
  29. package/lib/typescript/src/index.d.ts +1 -0
  30. package/lib/typescript/src/index.d.ts.map +1 -1
  31. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts +190 -10
  32. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts.map +1 -1
  33. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.cpp +5 -9
  34. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.hpp +1 -1
  35. package/nitrogen/generated/android/kotlin/com/margelo/nitro/acousticconnectrn/HybridAcousticConnectRNSpec.kt +2 -1
  36. package/nitrogen/generated/ios/AcousticConnectRN-Swift-Cxx-Umbrella.hpp +1 -0
  37. package/nitrogen/generated/ios/c++/HybridAcousticConnectRNSpecSwift.hpp +2 -1
  38. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec.swift +1 -1
  39. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec_cxx.swift +2 -25
  40. package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.hpp +2 -1
  41. package/package.json +6 -8
  42. package/plugin/build/withConnectAndroidConfig.d.ts +2 -2
  43. package/plugin/build/withConnectAndroidConfig.js +2 -2
  44. package/plugin/build/withConnectIosSigning.d.ts +1 -1
  45. package/plugin/build/withConnectIosSigning.js +1 -1
  46. package/plugin/src/withConnectAndroidConfig.ts +2 -2
  47. package/plugin/src/withConnectIosSigning.ts +1 -1
  48. package/scripts/gradleParser.js +1 -1
  49. package/src/TLTRN.ts +125 -4
  50. package/src/components/Connect.tsx +150 -27
  51. package/src/index.ts +5 -0
  52. package/src/specs/react-native-acoustic-connect.nitro.ts +192 -10
  53. package/Examples/SampleUI/.bundle/config +0 -2
  54. package/Examples/SampleUI/.detoxrc.js +0 -83
  55. package/Examples/SampleUI/.eslintrc.js +0 -4
  56. package/Examples/SampleUI/.prettierrc.js +0 -7
  57. package/Examples/SampleUI/.watchmanconfig +0 -1
  58. package/Examples/SampleUI/App.js +0 -1
  59. package/Examples/SampleUI/Gemfile +0 -10
  60. package/Examples/SampleUI/Gemfile.lock +0 -121
  61. package/Examples/SampleUI/README.md +0 -79
  62. package/Examples/SampleUI/__tests__/App.test.tsx +0 -17
  63. package/Examples/SampleUI/android/app/build.gradle +0 -129
  64. package/Examples/SampleUI/android/app/debug.keystore +0 -0
  65. package/Examples/SampleUI/android/app/proguard-rules.pro +0 -10
  66. package/Examples/SampleUI/android/app/src/debug/AndroidManifest.xml +0 -9
  67. package/Examples/SampleUI/android/app/src/main/AndroidManifest.xml +0 -31
  68. package/Examples/SampleUI/android/app/src/main/java/com/sampleui/MainActivity.kt +0 -30
  69. package/Examples/SampleUI/android/app/src/main/java/com/sampleui/MainApplication.kt +0 -53
  70. package/Examples/SampleUI/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -37
  71. package/Examples/SampleUI/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  72. package/Examples/SampleUI/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  73. package/Examples/SampleUI/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  74. package/Examples/SampleUI/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  75. package/Examples/SampleUI/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  76. package/Examples/SampleUI/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  77. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  78. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  79. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  80. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  81. package/Examples/SampleUI/android/app/src/main/res/values/strings.xml +0 -3
  82. package/Examples/SampleUI/android/app/src/main/res/values/styles.xml +0 -9
  83. package/Examples/SampleUI/android/build.gradle +0 -21
  84. package/Examples/SampleUI/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  85. package/Examples/SampleUI/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  86. package/Examples/SampleUI/android/gradle.properties +0 -39
  87. package/Examples/SampleUI/android/gradlew +0 -252
  88. package/Examples/SampleUI/android/gradlew.bat +0 -94
  89. package/Examples/SampleUI/android/settings.gradle +0 -21
  90. package/Examples/SampleUI/app.json +0 -51
  91. package/Examples/SampleUI/assets/fonts/Abel-Regular.ttf +0 -0
  92. package/Examples/SampleUI/assets/fonts/NotoSans-Regular.ttf +0 -0
  93. package/Examples/SampleUI/assets/images/android-icon.png +0 -0
  94. package/Examples/SampleUI/assets/images/artist-1.jpg +0 -0
  95. package/Examples/SampleUI/assets/images/artist-2.jpg +0 -0
  96. package/Examples/SampleUI/assets/images/avatar.png +0 -0
  97. package/Examples/SampleUI/assets/images/beach.jpg +0 -0
  98. package/Examples/SampleUI/assets/images/bridge.jpg +0 -0
  99. package/Examples/SampleUI/assets/images/chameleon.jpg +0 -0
  100. package/Examples/SampleUI/assets/images/city.jpg +0 -0
  101. package/Examples/SampleUI/assets/images/email-icon.png +0 -0
  102. package/Examples/SampleUI/assets/images/favorite.png +0 -0
  103. package/Examples/SampleUI/assets/images/forest.jpg +0 -0
  104. package/Examples/SampleUI/assets/images/paper-icon.png +0 -0
  105. package/Examples/SampleUI/assets/images/players-2.jpg +0 -0
  106. package/Examples/SampleUI/assets/images/players.jpg +0 -0
  107. package/Examples/SampleUI/assets/images/restaurant-1.jpg +0 -0
  108. package/Examples/SampleUI/assets/images/restaurant-2.jpg +0 -0
  109. package/Examples/SampleUI/assets/images/song-1.jpg +0 -0
  110. package/Examples/SampleUI/assets/images/song-2.jpg +0 -0
  111. package/Examples/SampleUI/assets/images/splash.png +0 -0
  112. package/Examples/SampleUI/assets/images/strawberries.jpg +0 -0
  113. package/Examples/SampleUI/assets/images/wrecked-ship.jpg +0 -0
  114. package/Examples/SampleUI/assets/styles/fonts.css +0 -47
  115. package/Examples/SampleUI/babel.config.js +0 -22
  116. package/Examples/SampleUI/index.js +0 -9
  117. package/Examples/SampleUI/ios/.xcode.env +0 -11
  118. package/Examples/SampleUI/ios/Podfile +0 -71
  119. package/Examples/SampleUI/ios/Podfile.lock +0 -2276
  120. package/Examples/SampleUI/ios/SampleUI/AppDelegate.h +0 -7
  121. package/Examples/SampleUI/ios/SampleUI/AppDelegate.mm +0 -31
  122. package/Examples/SampleUI/ios/SampleUI/Images.xcassets/AppIcon.appiconset/Contents.json +0 -53
  123. package/Examples/SampleUI/ios/SampleUI/Images.xcassets/Contents.json +0 -6
  124. package/Examples/SampleUI/ios/SampleUI/Info.plist +0 -52
  125. package/Examples/SampleUI/ios/SampleUI/LaunchScreen.storyboard +0 -47
  126. package/Examples/SampleUI/ios/SampleUI/PrivacyInfo.xcprivacy +0 -48
  127. package/Examples/SampleUI/ios/SampleUI/main.m +0 -10
  128. package/Examples/SampleUI/ios/SampleUI.xcodeproj/project.pbxproj +0 -785
  129. package/Examples/SampleUI/ios/SampleUI.xcodeproj/xcshareddata/xcschemes/SampleUI.xcscheme +0 -105
  130. package/Examples/SampleUI/ios/SampleUI.xcworkspace/contents.xcworkspacedata +0 -10
  131. package/Examples/SampleUI/ios/SampleUITests/Info.plist +0 -24
  132. package/Examples/SampleUI/ios/SampleUITests/SampleUITests.m +0 -66
  133. package/Examples/SampleUI/jest.config.js +0 -3
  134. package/Examples/SampleUI/metro.config.js +0 -54
  135. package/Examples/SampleUI/package.json +0 -65
  136. package/Examples/SampleUI/scripts/integration-test-android.sh +0 -292
  137. package/Examples/SampleUI/src/DrawerItems.tsx +0 -322
  138. package/Examples/SampleUI/src/ExampleList.tsx +0 -175
  139. package/Examples/SampleUI/src/Examples/ActivityIndicatorExample.tsx +0 -73
  140. package/Examples/SampleUI/src/Examples/AnimatedFABExample/AnimatedFABExample.tsx +0 -220
  141. package/Examples/SampleUI/src/Examples/AnimatedFABExample/CustomFAB.tsx +0 -70
  142. package/Examples/SampleUI/src/Examples/AnimatedFABExample/CustomFABControls.tsx +0 -146
  143. package/Examples/SampleUI/src/Examples/AnimatedFABExample/index.ts +0 -1
  144. package/Examples/SampleUI/src/Examples/AppbarExample.tsx +0 -263
  145. package/Examples/SampleUI/src/Examples/AvatarExample.tsx +0 -76
  146. package/Examples/SampleUI/src/Examples/BadgeExample.tsx +0 -97
  147. package/Examples/SampleUI/src/Examples/BannerExample.tsx +0 -152
  148. package/Examples/SampleUI/src/Examples/BottomNavigationBarExample.tsx +0 -94
  149. package/Examples/SampleUI/src/Examples/BottomNavigationExample.tsx +0 -205
  150. package/Examples/SampleUI/src/Examples/ButtonExample.tsx +0 -405
  151. package/Examples/SampleUI/src/Examples/CardExample.tsx +0 -245
  152. package/Examples/SampleUI/src/Examples/CheckboxExample.tsx +0 -87
  153. package/Examples/SampleUI/src/Examples/CheckboxItemExample.tsx +0 -72
  154. package/Examples/SampleUI/src/Examples/ChipExample.tsx +0 -432
  155. package/Examples/SampleUI/src/Examples/DataTableExample.tsx +0 -128
  156. package/Examples/SampleUI/src/Examples/DialogExample.tsx +0 -217
  157. package/Examples/SampleUI/src/Examples/Dialogs/DialogTextComponent.tsx +0 -31
  158. package/Examples/SampleUI/src/Examples/Dialogs/DialogTrackingTest.tsx +0 -307
  159. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithCustomColors.tsx +0 -57
  160. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithDismissableBackButton.tsx +0 -38
  161. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithIcon.tsx +0 -42
  162. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithLoadingIndicator.tsx +0 -48
  163. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithLongText.tsx +0 -81
  164. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithRadioBtns.tsx +0 -111
  165. package/Examples/SampleUI/src/Examples/Dialogs/UndismissableDialog.tsx +0 -30
  166. package/Examples/SampleUI/src/Examples/Dialogs/index.tsx +0 -44
  167. package/Examples/SampleUI/src/Examples/DividerExample.tsx +0 -30
  168. package/Examples/SampleUI/src/Examples/FABExample.tsx +0 -226
  169. package/Examples/SampleUI/src/Examples/IconButtonExample.tsx +0 -230
  170. package/Examples/SampleUI/src/Examples/IconExample.tsx +0 -50
  171. package/Examples/SampleUI/src/Examples/ListAccordionExample.tsx +0 -65
  172. package/Examples/SampleUI/src/Examples/ListAccordionGroupExample.tsx +0 -80
  173. package/Examples/SampleUI/src/Examples/ListItemExample.tsx +0 -310
  174. package/Examples/SampleUI/src/Examples/ListSectionExample.tsx +0 -159
  175. package/Examples/SampleUI/src/Examples/MaterialBottomTabNavigatorExample.tsx +0 -87
  176. package/Examples/SampleUI/src/Examples/MenuExample.tsx +0 -211
  177. package/Examples/SampleUI/src/Examples/ProgressBarExample.tsx +0 -142
  178. package/Examples/SampleUI/src/Examples/RadioButtonExample.tsx +0 -104
  179. package/Examples/SampleUI/src/Examples/RadioButtonGroupExample.tsx +0 -67
  180. package/Examples/SampleUI/src/Examples/RadioButtonItemExample.tsx +0 -77
  181. package/Examples/SampleUI/src/Examples/SearchbarExample.tsx +0 -249
  182. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonCustomColorCheck.tsx +0 -93
  183. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonDefault.tsx +0 -49
  184. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonDisabled.tsx +0 -47
  185. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselect.tsx +0 -50
  186. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselectIcons.tsx +0 -49
  187. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselectRealCase.tsx +0 -114
  188. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonOnlyIcons.tsx +0 -40
  189. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonOnlyIconsWithCheck.tsx +0 -43
  190. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonRealCase.tsx +0 -97
  191. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonWithDensity.tsx +0 -47
  192. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonWithSelectedCheck.tsx +0 -52
  193. package/Examples/SampleUI/src/Examples/SegmentedButtons/index.ts +0 -9
  194. package/Examples/SampleUI/src/Examples/SegmentedButtonsExample.tsx +0 -57
  195. package/Examples/SampleUI/src/Examples/SnackbarExample.tsx +0 -141
  196. package/Examples/SampleUI/src/Examples/SurfaceExample.tsx +0 -130
  197. package/Examples/SampleUI/src/Examples/SwitchExample.tsx +0 -105
  198. package/Examples/SampleUI/src/Examples/TeamDetails.tsx +0 -291
  199. package/Examples/SampleUI/src/Examples/TeamsList.tsx +0 -57
  200. package/Examples/SampleUI/src/Examples/TextExample.tsx +0 -132
  201. package/Examples/SampleUI/src/Examples/TextInputExample.tsx +0 -914
  202. package/Examples/SampleUI/src/Examples/ThemeExample.tsx +0 -41
  203. package/Examples/SampleUI/src/Examples/ThemingWithReactNavigation.tsx +0 -75
  204. package/Examples/SampleUI/src/Examples/ToggleButtonExample.tsx +0 -128
  205. package/Examples/SampleUI/src/Examples/TooltipExample.tsx +0 -191
  206. package/Examples/SampleUI/src/Examples/TouchableRippleExample.tsx +0 -37
  207. package/Examples/SampleUI/src/RootNavigator.tsx +0 -95
  208. package/Examples/SampleUI/src/ScreenWrapper.tsx +0 -67
  209. package/Examples/SampleUI/src/components/ActivityIndicator.tsx +0 -254
  210. package/Examples/SampleUI/src/components/Appbar/Appbar.tsx +0 -364
  211. package/Examples/SampleUI/src/components/Appbar/AppbarAction.tsx +0 -132
  212. package/Examples/SampleUI/src/components/Appbar/AppbarBackAction.tsx +0 -77
  213. package/Examples/SampleUI/src/components/Appbar/AppbarBackIcon.tsx +0 -52
  214. package/Examples/SampleUI/src/components/Appbar/AppbarContent.tsx +0 -249
  215. package/Examples/SampleUI/src/components/Appbar/AppbarHeader.tsx +0 -174
  216. package/Examples/SampleUI/src/components/Appbar/index.ts +0 -22
  217. package/Examples/SampleUI/src/components/Appbar/utils.ts +0 -188
  218. package/Examples/SampleUI/src/components/Avatar/Avatar.tsx +0 -8
  219. package/Examples/SampleUI/src/components/Avatar/AvatarIcon.tsx +0 -87
  220. package/Examples/SampleUI/src/components/Avatar/AvatarImage.tsx +0 -128
  221. package/Examples/SampleUI/src/components/Avatar/AvatarText.tsx +0 -127
  222. package/Examples/SampleUI/src/components/Badge.tsx +0 -138
  223. package/Examples/SampleUI/src/components/Banner.tsx +0 -302
  224. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigation.tsx +0 -643
  225. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigationBar.tsx +0 -1039
  226. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigationRouteScreen.tsx +0 -31
  227. package/Examples/SampleUI/src/components/BottomNavigation/utils.ts +0 -70
  228. package/Examples/SampleUI/src/components/Button/Button.tsx +0 -503
  229. package/Examples/SampleUI/src/components/Button/utils.tsx +0 -272
  230. package/Examples/SampleUI/src/components/Card/Card.tsx +0 -373
  231. package/Examples/SampleUI/src/components/Card/CardActions.tsx +0 -74
  232. package/Examples/SampleUI/src/components/Card/CardContent.tsx +0 -99
  233. package/Examples/SampleUI/src/components/Card/CardCover.tsx +0 -96
  234. package/Examples/SampleUI/src/components/Card/CardTitle.tsx +0 -236
  235. package/Examples/SampleUI/src/components/Card/utils.tsx +0 -110
  236. package/Examples/SampleUI/src/components/Checkbox/Checkbox.tsx +0 -78
  237. package/Examples/SampleUI/src/components/Checkbox/CheckboxAndroid.tsx +0 -180
  238. package/Examples/SampleUI/src/components/Checkbox/CheckboxIOS.tsx +0 -104
  239. package/Examples/SampleUI/src/components/Checkbox/CheckboxItem.tsx +0 -236
  240. package/Examples/SampleUI/src/components/Checkbox/index.ts +0 -19
  241. package/Examples/SampleUI/src/components/Checkbox/utils.ts +0 -183
  242. package/Examples/SampleUI/src/components/Chip/Chip.tsx +0 -513
  243. package/Examples/SampleUI/src/components/Chip/helpers.tsx +0 -322
  244. package/Examples/SampleUI/src/components/CrossFadeIcon.tsx +0 -140
  245. package/Examples/SampleUI/src/components/DataTable/DataTable.tsx +0 -138
  246. package/Examples/SampleUI/src/components/DataTable/DataTableCell.tsx +0 -132
  247. package/Examples/SampleUI/src/components/DataTable/DataTableHeader.tsx +0 -82
  248. package/Examples/SampleUI/src/components/DataTable/DataTablePagination.tsx +0 -407
  249. package/Examples/SampleUI/src/components/DataTable/DataTableRow.tsx +0 -107
  250. package/Examples/SampleUI/src/components/DataTable/DataTableTitle.tsx +0 -208
  251. package/Examples/SampleUI/src/components/Dialog/Dialog.tsx +0 -191
  252. package/Examples/SampleUI/src/components/Dialog/DialogActions.tsx +0 -94
  253. package/Examples/SampleUI/src/components/Dialog/DialogContent.tsx +0 -54
  254. package/Examples/SampleUI/src/components/Dialog/DialogIcon.tsx +0 -100
  255. package/Examples/SampleUI/src/components/Dialog/DialogScrollArea.tsx +0 -88
  256. package/Examples/SampleUI/src/components/Dialog/DialogTitle.tsx +0 -94
  257. package/Examples/SampleUI/src/components/Divider.tsx +0 -102
  258. package/Examples/SampleUI/src/components/Drawer/Drawer.tsx +0 -8
  259. package/Examples/SampleUI/src/components/Drawer/DrawerCollapsedItem.tsx +0 -282
  260. package/Examples/SampleUI/src/components/Drawer/DrawerItem.tsx +0 -209
  261. package/Examples/SampleUI/src/components/Drawer/DrawerSection.tsx +0 -138
  262. package/Examples/SampleUI/src/components/FAB/AnimatedFAB.tsx +0 -619
  263. package/Examples/SampleUI/src/components/FAB/FAB.tsx +0 -371
  264. package/Examples/SampleUI/src/components/FAB/FABGroup.tsx +0 -532
  265. package/Examples/SampleUI/src/components/FAB/index.ts +0 -13
  266. package/Examples/SampleUI/src/components/FAB/utils.ts +0 -474
  267. package/Examples/SampleUI/src/components/HelperText/HelperText.tsx +0 -168
  268. package/Examples/SampleUI/src/components/HelperText/utils.ts +0 -30
  269. package/Examples/SampleUI/src/components/Icon.tsx +0 -170
  270. package/Examples/SampleUI/src/components/IconButton/IconButton.tsx +0 -234
  271. package/Examples/SampleUI/src/components/IconButton/utils.ts +0 -190
  272. package/Examples/SampleUI/src/components/List/List.tsx +0 -20
  273. package/Examples/SampleUI/src/components/List/ListAccordion.tsx +0 -391
  274. package/Examples/SampleUI/src/components/List/ListAccordionGroup.tsx +0 -88
  275. package/Examples/SampleUI/src/components/List/ListIcon.tsx +0 -79
  276. package/Examples/SampleUI/src/components/List/ListImage.tsx +0 -89
  277. package/Examples/SampleUI/src/components/List/ListItem.tsx +0 -313
  278. package/Examples/SampleUI/src/components/List/ListSection.tsx +0 -87
  279. package/Examples/SampleUI/src/components/List/ListSubheader.tsx +0 -79
  280. package/Examples/SampleUI/src/components/List/utils.ts +0 -113
  281. package/Examples/SampleUI/src/components/MaterialCommunityIcon.tsx +0 -121
  282. package/Examples/SampleUI/src/components/Menu/Menu.tsx +0 -711
  283. package/Examples/SampleUI/src/components/Menu/MenuItem.tsx +0 -257
  284. package/Examples/SampleUI/src/components/Menu/utils.ts +0 -110
  285. package/Examples/SampleUI/src/components/Modal.tsx +0 -245
  286. package/Examples/SampleUI/src/components/Portal/Portal.tsx +0 -69
  287. package/Examples/SampleUI/src/components/Portal/PortalConsumer.tsx +0 -44
  288. package/Examples/SampleUI/src/components/Portal/PortalHost.tsx +0 -143
  289. package/Examples/SampleUI/src/components/Portal/PortalManager.tsx +0 -54
  290. package/Examples/SampleUI/src/components/ProgressBar.tsx +0 -292
  291. package/Examples/SampleUI/src/components/RadioButton/RadioButton.tsx +0 -86
  292. package/Examples/SampleUI/src/components/RadioButton/RadioButtonAndroid.tsx +0 -202
  293. package/Examples/SampleUI/src/components/RadioButton/RadioButtonGroup.tsx +0 -67
  294. package/Examples/SampleUI/src/components/RadioButton/RadioButtonIOS.tsx +0 -130
  295. package/Examples/SampleUI/src/components/RadioButton/RadioButtonItem.tsx +0 -268
  296. package/Examples/SampleUI/src/components/RadioButton/index.ts +0 -22
  297. package/Examples/SampleUI/src/components/RadioButton/utils.ts +0 -37
  298. package/Examples/SampleUI/src/components/Searchbar.tsx +0 -459
  299. package/Examples/SampleUI/src/components/SegmentedButtons/SegmentedButtonItem.tsx +0 -271
  300. package/Examples/SampleUI/src/components/SegmentedButtons/SegmentedButtons.tsx +0 -197
  301. package/Examples/SampleUI/src/components/SegmentedButtons/utils.ts +0 -179
  302. package/Examples/SampleUI/src/components/Snackbar.tsx +0 -430
  303. package/Examples/SampleUI/src/components/Surface.tsx +0 -376
  304. package/Examples/SampleUI/src/components/Switch/Switch.tsx +0 -108
  305. package/Examples/SampleUI/src/components/Switch/utils.ts +0 -113
  306. package/Examples/SampleUI/src/components/TextInput/Addons/Outline.tsx +0 -64
  307. package/Examples/SampleUI/src/components/TextInput/Addons/Underline.tsx +0 -78
  308. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputAdornment.tsx +0 -208
  309. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputAffix.tsx +0 -212
  310. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputIcon.tsx +0 -195
  311. package/Examples/SampleUI/src/components/TextInput/Adornment/enums.tsx +0 -12
  312. package/Examples/SampleUI/src/components/TextInput/Adornment/types.tsx +0 -11
  313. package/Examples/SampleUI/src/components/TextInput/Adornment/utils.ts +0 -48
  314. package/Examples/SampleUI/src/components/TextInput/Label/InputLabel.tsx +0 -217
  315. package/Examples/SampleUI/src/components/TextInput/Label/LabelBackground.tsx +0 -100
  316. package/Examples/SampleUI/src/components/TextInput/TextInput.tsx +0 -572
  317. package/Examples/SampleUI/src/components/TextInput/TextInputFlat.tsx +0 -475
  318. package/Examples/SampleUI/src/components/TextInput/TextInputOutlined.tsx +0 -450
  319. package/Examples/SampleUI/src/components/TextInput/constants.tsx +0 -48
  320. package/Examples/SampleUI/src/components/TextInput/helpers.tsx +0 -612
  321. package/Examples/SampleUI/src/components/TextInput/types.tsx +0 -155
  322. package/Examples/SampleUI/src/components/ToggleButton/ToggleButton.tsx +0 -187
  323. package/Examples/SampleUI/src/components/ToggleButton/ToggleButtonGroup.tsx +0 -72
  324. package/Examples/SampleUI/src/components/ToggleButton/ToggleButtonRow.tsx +0 -107
  325. package/Examples/SampleUI/src/components/ToggleButton/index.ts +0 -16
  326. package/Examples/SampleUI/src/components/ToggleButton/utils.ts +0 -26
  327. package/Examples/SampleUI/src/components/Tooltip/Tooltip.tsx +0 -249
  328. package/Examples/SampleUI/src/components/Tooltip/utils.ts +0 -129
  329. package/Examples/SampleUI/src/components/TouchableRipple/Pressable.tsx +0 -41
  330. package/Examples/SampleUI/src/components/TouchableRipple/TouchableRipple.native.tsx +0 -145
  331. package/Examples/SampleUI/src/components/TouchableRipple/TouchableRipple.tsx +0 -317
  332. package/Examples/SampleUI/src/components/TouchableRipple/utils.ts +0 -66
  333. package/Examples/SampleUI/src/components/Typography/AnimatedText.tsx +0 -107
  334. package/Examples/SampleUI/src/components/Typography/Text.tsx +0 -184
  335. package/Examples/SampleUI/src/components/Typography/types.tsx +0 -5
  336. package/Examples/SampleUI/src/components/Typography/v2/Caption.tsx +0 -50
  337. package/Examples/SampleUI/src/components/Typography/v2/Headline.tsx +0 -52
  338. package/Examples/SampleUI/src/components/Typography/v2/Paragraph.tsx +0 -49
  339. package/Examples/SampleUI/src/components/Typography/v2/StyledText.tsx +0 -56
  340. package/Examples/SampleUI/src/components/Typography/v2/Subheading.tsx +0 -50
  341. package/Examples/SampleUI/src/components/Typography/v2/Text.tsx +0 -62
  342. package/Examples/SampleUI/src/components/Typography/v2/Title.tsx +0 -49
  343. package/Examples/SampleUI/src/components/Typography/v2/index.ts +0 -5
  344. package/Examples/SampleUI/src/core/PaperProvider.tsx +0 -122
  345. package/Examples/SampleUI/src/core/SafeAreaProviderCompat.tsx +0 -65
  346. package/Examples/SampleUI/src/core/settings.tsx +0 -23
  347. package/Examples/SampleUI/src/core/theming.tsx +0 -170
  348. package/Examples/SampleUI/src/index.native.tsx +0 -285
  349. package/Examples/SampleUI/src/index.tsx +0 -226
  350. package/Examples/SampleUI/src/react-navigation/index.tsx +0 -19
  351. package/Examples/SampleUI/src/react-navigation/navigators/createMaterialBottomTabNavigator.tsx +0 -72
  352. package/Examples/SampleUI/src/react-navigation/types.tsx +0 -126
  353. package/Examples/SampleUI/src/react-navigation/views/MaterialBottomTabView.tsx +0 -140
  354. package/Examples/SampleUI/src/styles/__tests__/fonts.test.js +0 -290
  355. package/Examples/SampleUI/src/styles/fonts.tsx +0 -143
  356. package/Examples/SampleUI/src/styles/overlay.tsx +0 -70
  357. package/Examples/SampleUI/src/styles/shadow.tsx +0 -109
  358. package/Examples/SampleUI/src/styles/themes/index.ts +0 -4
  359. package/Examples/SampleUI/src/styles/themes/v2/DarkTheme.tsx +0 -30
  360. package/Examples/SampleUI/src/styles/themes/v2/LightTheme.tsx +0 -30
  361. package/Examples/SampleUI/src/styles/themes/v2/colors.tsx +0 -277
  362. package/Examples/SampleUI/src/styles/themes/v3/DarkTheme.tsx +0 -66
  363. package/Examples/SampleUI/src/styles/themes/v3/LightTheme.tsx +0 -69
  364. package/Examples/SampleUI/src/styles/themes/v3/tokens.tsx +0 -230
  365. package/Examples/SampleUI/src/utils/BackHandler/BackHandler.native.tsx +0 -3
  366. package/Examples/SampleUI/src/utils/BackHandler/BackHandler.tsx +0 -11
  367. package/Examples/SampleUI/src/utils/addEventListener.tsx +0 -56
  368. package/Examples/SampleUI/src/utils/forwardRef.tsx +0 -23
  369. package/Examples/SampleUI/src/utils/getContrastingColor.tsx +0 -15
  370. package/Examples/SampleUI/src/utils/hasTouchHandler.tsx +0 -23
  371. package/Examples/SampleUI/src/utils/roundLayoutSize.ts +0 -2
  372. package/Examples/SampleUI/src/utils/splitStyles.ts +0 -60
  373. package/Examples/SampleUI/src/utils/useAnimatedValue.tsx +0 -9
  374. package/Examples/SampleUI/src/utils/useAnimatedValueArray.tsx +0 -13
  375. package/Examples/SampleUI/src/utils/useIsKeyboardShown.tsx +0 -55
  376. package/Examples/SampleUI/src/utils/useLayout.tsx +0 -29
  377. package/Examples/SampleUI/src/utils/useLazyRef.tsx +0 -11
  378. package/Examples/SampleUI/tsconfig.json +0 -3
  379. package/Examples/SampleUI/utils/index.ts +0 -1426
  380. package/cli/__tests__/doctor.test.mjs +0 -88
@@ -62,6 +62,7 @@ import com.margelo.nitro.acousticconnectrn.PushPermissionResult
62
62
  import com.margelo.nitro.acousticconnectrn.Variant_Boolean_String_Double
63
63
  import com.margelo.nitro.acousticconnectrn.Variant_NullType_Boolean
64
64
  import com.margelo.nitro.acousticconnectrn.Variant_NullType_String
65
+ import com.margelo.nitro.core.AnyMap
65
66
  import com.margelo.nitro.core.ArrayBuffer
66
67
  import com.margelo.nitro.core.NullType
67
68
  import com.margelo.nitro.core.Promise
@@ -70,6 +71,9 @@ import com.tl.uic.model.ScreenviewType
70
71
  import com.tl.uic.util.DialogUtil
71
72
  import com.tl.uic.util.LayoutUtil
72
73
  import com.tl.uic.util.keyboardview.KeyboardView
74
+ import org.json.JSONArray
75
+ import org.json.JSONException
76
+ import org.json.JSONObject
73
77
  import java.util.Objects
74
78
 
75
79
 
@@ -575,7 +579,12 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
575
579
  value: Double,
576
580
  moduleName: String
577
581
  ): Boolean {
578
- val result = EOCore.updateConfig(key, value.toString(), EOCore.getLifecycleObject(moduleName))
582
+ // Rendered through formatJsNumber, not Double.toString: EOCore stores
583
+ // config items as strings, and a JS 0 spelled "0.0" is not the same
584
+ // token as the "0" the JSON config files carry, so a consumer setting
585
+ // a whole-number item at runtime wrote a value that no longer matched
586
+ // what the same key looks like on iOS (a native number) or on disk.
587
+ val result = EOCore.updateConfig(key, formatJsNumber(value), EOCore.getLifecycleObject(moduleName))
579
588
  return result
580
589
  }
581
590
 
@@ -592,7 +601,8 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
592
601
  value: Variant_Boolean_String_Double,
593
602
  moduleName: String
594
603
  ): Boolean {
595
- val result = EOCore.updateConfig(key, value.toString(), EOCore.getLifecycleObject(moduleName))
604
+ val result =
605
+ EOCore.updateConfig(key, variantToString(value), EOCore.getLifecycleObject(moduleName))
596
606
  return result
597
607
  }
598
608
 
@@ -662,21 +672,59 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
662
672
  level: Double
663
673
  ): Boolean {
664
674
  val result = Connect.logCustomEvent(eventName, convertToMap(values), level.toInt())
665
- return result
675
+ return warnIfRejected(result, "logCustomEvent", eventName)
666
676
  }
667
677
 
668
678
  /**
669
679
  * Logs a signal with the specified values.
670
680
  *
671
- * @param values A map of values associated with the signal.
681
+ * Takes an [AnyMap] rather than a map of Nitro variants so JS callers can
682
+ * send arbitrary JSON — nested objects and arrays included. See
683
+ * [toSignalPayload] for why the nesting has to be rebuilt as
684
+ * [JSONObject]/[JSONArray] rather than handed over as plain Kotlin
685
+ * collections.
686
+ *
687
+ * @param values The signal payload; objects, arrays and scalars are all carried through.
672
688
  * @param level Set a custom log level to the event. This will override the configured log level for that event.
673
689
  * @return True if the operation was successful, false otherwise.
674
690
  */
675
691
  override fun logSignal(
676
- values: Map<String, Variant_Boolean_String_Double>,
692
+ values: AnyMap,
677
693
  level: Double
678
694
  ): Boolean {
679
- val result = Connect.logSignal(convertToMapAny(values), level.toInt())
695
+ val result = Connect.logSignal(toSignalPayload(values.toHashMap()), level.toInt())
696
+ return warnIfRejected(result, "logSignal")
697
+ }
698
+
699
+ /**
700
+ * Surfaces a `false` returned by a native logging call, and passes it
701
+ * through unchanged.
702
+ *
703
+ * The bridge's boolean means "the SDK accepted this for delivery", never
704
+ * "the collector received it" — nothing on the device knows the latter. But
705
+ * the *accepted* half was itself invisible: a `false` propagated to JS as a
706
+ * bare return value that the wrapper's callers almost never inspect, with
707
+ * nothing in logcat. Callers reporting "the event never arrived" had no way
708
+ * to tell a rejected call from a delivery problem. One line at warn level
709
+ * distinguishes them.
710
+ *
711
+ * Deliberately does not change the return value or throw: an analytics
712
+ * bridge must not turn a rejected event into an app-visible failure.
713
+ *
714
+ * @param result The value the native call returned.
715
+ * @param api Name of the bridge method, for the log line.
716
+ * @param detail Optional extra identifier, e.g. an event name.
717
+ * @return [result], unchanged.
718
+ */
719
+ private fun warnIfRejected(result: Boolean, api: String, detail: String? = null): Boolean {
720
+ if (!result) {
721
+ val suffix = if (detail != null) " ($detail)" else ""
722
+ Log.w(
723
+ TAG,
724
+ "[bridge] $api$suffix: the Connect SDK did not accept the event; nothing was queued " +
725
+ "for delivery. Check that the SDK is enabled and the payload is valid."
726
+ )
727
+ }
680
728
  return result
681
729
  }
682
730
 
@@ -697,8 +745,11 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
697
745
  * @param identifierValue Identifier value, e.g. "user@example.com".
698
746
  * @param signalType Optional signal type; defaults to "loggedIn" when omitted.
699
747
  * @param additionalParameters Optional extra key/value pairs merged into the
700
- * signal. Defaults to `{ "registrationMethod": "email" }` only when null
701
- * (omitted); an explicit map — including an empty one — is used as-is.
748
+ * signal. Defaults, only when null (omitted), to the method attribute the
749
+ * resolved signal type requires — `{ "loginMethod": "email" }` for
750
+ * `loggedIn`, `{ "registrationMethod": "email" }` otherwise (see
751
+ * [defaultIdentityParameters]). An explicit map — including an empty one
752
+ * — is used as-is.
702
753
  * @return A promise resolving to true if the signal was queued, false otherwise.
703
754
  */
704
755
  override fun logIdentity(
@@ -707,8 +758,8 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
707
758
  signalType: String?,
708
759
  additionalParameters: Map<String, String>?
709
760
  ): Promise<Boolean> {
710
- val params = additionalParameters ?: mapOf("registrationMethod" to "email")
711
761
  val resolvedSignalType = signalType ?: "loggedIn"
762
+ val params = additionalParameters ?: defaultIdentityParameters(resolvedSignalType)
712
763
  val result = params["url"]?.let { url ->
713
764
  Connect.logIdentificationEvent(
714
765
  identifierName,
@@ -723,7 +774,11 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
723
774
  signalType = resolvedSignalType,
724
775
  additionalParameters = params
725
776
  )
726
- return Promise.resolved(result)
777
+ // An identity signal that the SDK accepts can still be rejected
778
+ // downstream by schema validation — a mismatched method attribute has
779
+ // cost a customer 22 signals while every call reported success. The
780
+ // bridge cannot see that; it can at least report the half it does see.
781
+ return Promise.resolved(warnIfRejected(result, "logIdentity", resolvedSignalType))
727
782
  }
728
783
 
729
784
  /**
@@ -857,15 +912,78 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
857
912
  }
858
913
  }
859
914
 
915
+ /**
916
+ * Whether the bridge may touch capture at all.
917
+ *
918
+ * `disable()` reaches `Tealeaf.disable()`, which unregisters the activity
919
+ * lifecycle callbacks and clears the enabled flag — enough on iOS, where
920
+ * `<Connect>` only advances the current screen name. On Android the same
921
+ * component also drives capture explicitly on every navigation
922
+ * (`logScreenViewPageName` + `logScreenLayout`), and those paths used to run
923
+ * regardless of the flag: `setCurrentScreenName` called through to
924
+ * `Tealeaf.resumeTealeaf`, which resumes logging, and `logScreenLayout`
925
+ * captured a full layout. The net effect was that `disable()` silenced
926
+ * capture on iOS but not on Android, for an app doing nothing unusual.
927
+ *
928
+ * Checked here rather than in JS so every caller is covered, including apps
929
+ * that call the bridge methods directly.
930
+ */
931
+ private fun isCaptureAllowed(): Boolean = Connect.isEnabled()
932
+
860
933
  /**
861
934
  * Requests that the framework save the current application page name.
862
935
  *
936
+ * Sets the name and nothing else, which is what the name promises and what
937
+ * iOS has always done — `TLFApplicationHelper.setCurrentScreenName:` just
938
+ * assigns `TLFScreenViewManager`'s current screen view name.
939
+ *
940
+ * `<Connect>` calls this on every touch: `onStartShouldSetResponderCapture`
941
+ * needs the name current so the click that follows is attributed to the
942
+ * right screen. It therefore has to be cheap, and on Android it was not. It
943
+ * used to be `Connect.resumeConnect` → `Tealeaf.resumeTealeaf`, which does
944
+ * four things at once: sets the name, emits a screenview LOAD, re-arms
945
+ * capture, and **captures a full screen layout**. Only the first is wanted
946
+ * here. The layout put a message of tens to hundreds of KB on the wire per
947
+ * tap on Android, where the same call on iOS sends nothing.
948
+ *
949
+ * That volume is not merely wasteful. EOCore's disk cache holds at most
950
+ * `MaxNumberOfFilesToCache` (5) chunks between post cycles and silently
951
+ * discards the rest while posting is healthy, so a tap-heavy screen loses
952
+ * whole batches: in a customer session, a `DeliveryOptionsScreen` LOAD and
953
+ * the first 8 s of capture on it went missing that way.
954
+ *
955
+ * Dropping the re-arm with it is safe, and was verified on-device rather
956
+ * than assumed: `logScreenLayout` below still calls `resumeConnect` on
957
+ * every navigation and on first paint, which arms capture before any touch
958
+ * can reach this method. Measured on the bare-workflow sample, twelve taps
959
+ * on one screen went from 21 layout messages (586 KB) to 4 (67 KB) with all
960
+ * twelve clicks still captured.
961
+ *
962
+ * Screenview and layout belong to the navigation path, which goes through
963
+ * `logScreenLayout` below and is unchanged.
964
+ *
863
965
  * @param logicalPageName The logical page name to be set.
864
966
  * @return True if the operation was successful, false otherwise.
865
967
  */
866
968
  override fun setCurrentScreenName(logicalPageName: String): Boolean {
867
- val result = resumeConnect(getCurrentActivity(), logicalPageName, false)
868
- return result
969
+ // Nothing should advance capture state while disabled. Cheaper than it
970
+ // was — this no longer captures a layout — but still the wrong thing to
971
+ // do behind a `disable()`.
972
+ if (!isCaptureAllowed()) return false
973
+ // Guarded because of where this runs, not because the call is expected to
974
+ // fail: `<Connect>` invokes it from `onStartShouldSetResponderCapture`, so
975
+ // this is the one bridge method on the per-touch path. An exception out of
976
+ // the SDK here would surface inside React's responder negotiation on every
977
+ // tap, taking touch handling down with it. Report the failure instead — the
978
+ // click that follows is then attributed to the previous screen, which is
979
+ // wrong but survivable.
980
+ return try {
981
+ Connect.setCurrentLogicalPageName(logicalPageName)
982
+ true
983
+ } catch (e: Exception) {
984
+ Log.v(TAG, "setCurrentScreenName error: ${e.message}")
985
+ false
986
+ }
869
987
  }
870
988
 
871
989
  /**
@@ -876,8 +994,14 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
876
994
  * @return True if the operation was successful, false otherwise.
877
995
  */
878
996
  override fun logScreenViewContextLoad(logicalPageName: Variant_NullType_String?, referrer: Variant_NullType_String?): Boolean {
879
- val result = logScreenview(getCurrentActivity()!!, logicalPageName?.asSecondOrNull().toString(), ScreenviewType.LOAD, referrer?.asSecondOrNull());
880
- return result
997
+ // Emits a screenview message; nothing should reach the queue while disabled.
998
+ if (!isCaptureAllowed()) return false
999
+ // No activity means nothing to log a screenview against. This used to be
1000
+ // a force-unwrap, which turned a backgrounded or not-yet-attached activity
1001
+ // into a crash; the sample now calls this method directly, so the path is
1002
+ // easy to reach from JS.
1003
+ val activity = getCurrentActivity() ?: return false
1004
+ return logScreenview(activity, logicalPageName?.asSecondOrNull().toString(), ScreenviewType.LOAD, referrer?.asSecondOrNull())
881
1005
  }
882
1006
 
883
1007
  /**
@@ -888,32 +1012,138 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
888
1012
  * @return True if the operation was successful, false otherwise.
889
1013
  */
890
1014
  override fun logScreenViewContextUnload(logicalPageName: Variant_NullType_String?, referrer: Variant_NullType_String?): Boolean {
891
- val result = logScreenview(getCurrentActivity()!!, logicalPageName?.asSecondOrNull().toString(), ScreenviewType.UNLOAD, referrer?.asSecondOrNull());
892
- return result
1015
+ // Emits a screenview message; nothing should reach the queue while disabled.
1016
+ if (!isCaptureAllowed()) return false
1017
+ // No activity means nothing to log a screenview against. This used to be
1018
+ // a force-unwrap, which turned a backgrounded or not-yet-attached activity
1019
+ // into a crash; the sample now calls this method directly, so the path is
1020
+ // easy to reach from JS.
1021
+ val activity = getCurrentActivity() ?: return false
1022
+ return logScreenview(activity, logicalPageName?.asSecondOrNull().toString(), ScreenviewType.UNLOAD, referrer?.asSecondOrNull())
893
1023
  }
894
1024
 
895
1025
  /**
896
1026
  * Log Current Screen Layout using native side background thread.
897
1027
  *
898
1028
  * @param name Page name or title e.g. "Login View Controller"; Must not be empty.
899
- * @param delay The delay in milliseconds before logging the event.
1029
+ * @param delay The delay in milliseconds before logging the event. A negative
1030
+ * value means "use the `CaptureLayoutDelay` configured for this
1031
+ * screen", which is what the JS wrapper sends when the caller
1032
+ * names no delay.
900
1033
  * @return True if the operation was successful, false otherwise.
901
1034
  */
902
1035
  override fun logScreenLayout(name: String, delay: Double): Boolean {
903
- setCurrentScreenName(name)
1036
+ // The wrapper calls this on every Android navigation.
1037
+ if (!isCaptureAllowed()) return false
1038
+ // Resume explicitly rather than via `setCurrentScreenName`, which now only
1039
+ // sets the name. Navigation is where resuming belongs: `resumeTealeaf`
1040
+ // re-enables capture for the screen being entered (`_isCaptureScreenContentsEnabled`)
1041
+ // after a `pauseTealeaf`, honouring the screen's layout config. Calling it
1042
+ // here keeps this path byte-identical to what it did before that split.
1043
+ //
1044
+ // The result is advisory on purpose: a false means the resume did not take,
1045
+ // which is not a reason to skip the screenview and layout that follow — they
1046
+ // are what the caller asked for. Treating it as fatal would suppress capture
1047
+ // in cases that capture fine today.
1048
+ resumeConnect(getCurrentActivity(), name, false)
1049
+ // The 3-arg overload takes a nullable Activity, so this one is safe to pass
1050
+ // through — unlike the 4-arg overload the context methods use.
904
1051
  logScreenview(getCurrentActivity(), name, ScreenviewType.LOAD)
905
1052
  var result = false
906
- if (LayoutUtil.canCaptureUserEvents(null, name)) {
907
- result = logScreenLayout(
908
- Objects.requireNonNull<Activity?>(getCurrentActivity()),
1053
+ // The layout capture below needs a real activity: it used to go through
1054
+ // Objects.requireNonNull, which threw when the activity had gone away
1055
+ // between the check above and here. Skip the capture instead and report
1056
+ // false — this runs on every Android navigation, so a throw here is a
1057
+ // crash on an ordinary screen change.
1058
+ val activity = getCurrentActivity()
1059
+ if (activity != null && LayoutUtil.canCaptureUserEvents(null, name)) {
1060
+ result = logAutomaticScreenLayout(
1061
+ activity,
909
1062
  name,
910
- if (delay.toInt() < 0) 300 else delay.toInt(),
911
- true
1063
+ resolveCaptureLayoutDelayMs(name, delay)
912
1064
  )
913
1065
  }
914
1066
  return result
915
1067
  }
916
1068
 
1069
+ /**
1070
+ * Captures the layout of [activity] as an *automatic* capture — the kind
1071
+ * the wrapper triggers itself, on navigation or behind a dialog — rather
1072
+ * than a manual `logScreenLayout` API call from the host app.
1073
+ *
1074
+ * Every wrapper-initiated capture must go through here, because the
1075
+ * distinction is what makes the configured `ScreenShot` value reach the
1076
+ * native screenshot gate at all:
1077
+ *
1078
+ * - `Connect`'s four-argument overload hardcodes `manualLog = true`, and
1079
+ * the native gate reads the configured `ScreenShot` only on the
1080
+ * `manualLog = false` branch. Passing a literal `true` for the screenshot
1081
+ * flag — which every wrapper call site used to do — therefore took the
1082
+ * manual branch unconditionally, so `ScreenShot: false` could not be
1083
+ * honoured from config and a full-page image shipped in every layout
1084
+ * message regardless. Hence the five-argument overload, with
1085
+ * `manualLog = false`.
1086
+ * - [LayoutUtil.canTakeScreenShot] resolves the same merged layout rule the
1087
+ * native automatic path uses (global settings as a baseline, any
1088
+ * per-screen rule applied over them). It is preferred over reading
1089
+ * `ScreenShot` directly because it is `has()`-guarded: a per-screen rule
1090
+ * that omits the key defaults to capturing rather than throwing a
1091
+ * `JSONException`, which higher up is swallowed and costs the whole
1092
+ * layout message. Its first argument may be null while the page name is
1093
+ * non-empty, the same pattern as `canCaptureUserEvents(null, name)`.
1094
+ *
1095
+ * Note `CaptureScreenshotOn` is not consulted anywhere on Android: its only
1096
+ * native reader has no callers, so `ScreenShot` is the one wired-up switch.
1097
+ *
1098
+ * [activity] is nullable to match the five-argument overload; callers that
1099
+ * need a non-null one check or assert before calling.
1100
+ */
1101
+ private fun logAutomaticScreenLayout(
1102
+ activity: Activity?,
1103
+ name: String,
1104
+ delayMs: Int
1105
+ ): Boolean {
1106
+ return logScreenLayout(
1107
+ activity,
1108
+ name,
1109
+ delayMs,
1110
+ false,
1111
+ LayoutUtil.canTakeScreenShot(null, name)
1112
+ )
1113
+ }
1114
+
1115
+ /**
1116
+ * Resolves the capture delay, in milliseconds, to apply for [name].
1117
+ *
1118
+ * A non-negative [delay] is the caller's explicit choice and passes
1119
+ * straight through. A negative one defers to `CaptureLayoutDelay` in the
1120
+ * layout config, which is what makes that setting reach the React Native
1121
+ * wrapper at all — the wrapper used to hardcode 0 here, so the capture
1122
+ * fired at the start of the screen transition and the configured value
1123
+ * was inert.
1124
+ *
1125
+ * [LayoutUtil.getLayoutInfo] returns the merged rule for the screen: the
1126
+ * global settings as a baseline with any per-screen rule applied over
1127
+ * them, so this picks up either without re-implementing the precedence.
1128
+ * It reads the config off disk, so a malformed or absent block falls back
1129
+ * to [DEFAULT_CAPTURE_LAYOUT_DELAY_MS] rather than propagating a throw
1130
+ * into a logging call.
1131
+ */
1132
+ internal fun resolveCaptureLayoutDelayMs(name: String, delay: Double): Int {
1133
+ if (delay >= 0) {
1134
+ return delay.toInt()
1135
+ }
1136
+ return try {
1137
+ LayoutUtil.getLayoutInfo(name)
1138
+ ?.optInt(CAPTURE_LAYOUT_DELAY_KEY, DEFAULT_CAPTURE_LAYOUT_DELAY_MS)
1139
+ ?.coerceAtLeast(0)
1140
+ ?: DEFAULT_CAPTURE_LAYOUT_DELAY_MS
1141
+ } catch (e: Exception) {
1142
+ Log.w(TAG, "Could not read $CAPTURE_LAYOUT_DELAY_KEY for \"$name\"; using ${DEFAULT_CAPTURE_LAYOUT_DELAY_MS}ms.", e)
1143
+ DEFAULT_CAPTURE_LAYOUT_DELAY_MS
1144
+ }
1145
+ }
1146
+
917
1147
  /**
918
1148
  * Logs a dialog show event with the specified dialog information.
919
1149
  *
@@ -950,12 +1180,12 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
950
1180
  } else {
951
1181
  Log.v(TAG, "Warning: Could not find dialog object for $dialogId after delay")
952
1182
  // Fallback to regular screen layout capture
953
- logScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 0, true)
1183
+ logAutomaticScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 0)
954
1184
  }
955
1185
  } catch (e: Exception) {
956
1186
  Log.v(TAG, "Error in delayed dialog capture: ${e.message}")
957
1187
  // Fallback to regular screen layout capture
958
- logScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 0, true)
1188
+ logAutomaticScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 0)
959
1189
  }
960
1190
  }, DIALOG_CAPTURE_DELAY_MS) // Use configurable delay
961
1191
 
@@ -974,7 +1204,7 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
974
1204
  }
975
1205
  } else {
976
1206
  // Default fallback
977
- result = logScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 300, true)
1207
+ result = logAutomaticScreenLayout(Objects.requireNonNull<Activity?>(getCurrentActivity()), dialogTitle, 300)
978
1208
  }
979
1209
  }
980
1210
  } catch (e: Exception) {
@@ -1187,7 +1417,7 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1187
1417
  for (key in values.keys) {
1188
1418
  val value = values[key]
1189
1419
  if (value != null) {
1190
- eventValues[key] = value.toString()
1420
+ eventValues[key] = variantToString(value)
1191
1421
  }
1192
1422
  }
1193
1423
 
@@ -1200,9 +1430,83 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1200
1430
  return result
1201
1431
  }
1202
1432
 
1433
+ /**
1434
+ * Unwraps a Nitro variant to the underlying JS value it carries — a
1435
+ * [Boolean], [String], or [Double].
1436
+ *
1437
+ * The generated `Variant_*` type is a sealed **data** class, so calling
1438
+ * `toString()` on the variant itself yields the case wrapper
1439
+ * (`"Second(value=pro)"`) instead of the value (`"pro"`). Every conversion
1440
+ * that reads a variant must unwrap it first. Mirrors the iOS bridge's
1441
+ * `ConnectRNParsing.convertVariantToAny`, keeping emitted payloads
1442
+ * identical across platforms.
1443
+ *
1444
+ * @param value The variant to unwrap.
1445
+ * @return The wrapped Boolean, String, or Double.
1446
+ */
1447
+ private fun unwrapVariant(value: Variant_Boolean_String_Double): Any =
1448
+ value.match(first = { it }, second = { it }, third = { it })
1449
+
1450
+ /**
1451
+ * Unwraps a Nitro variant (see [unwrapVariant]) and renders it as a string,
1452
+ * for the SDK entry points that take `HashMap<String, String>` payloads.
1453
+ *
1454
+ * Booleans render as `"true"`/`"false"`, strings pass through unchanged,
1455
+ * and numbers go through [formatJsNumber] so they read the way the same
1456
+ * JS value reads on iOS.
1457
+ *
1458
+ * @param value The variant to stringify.
1459
+ * @return The wrapped value's string form.
1460
+ */
1461
+ private fun variantToString(value: Variant_Boolean_String_Double): String =
1462
+ when (val unwrapped = unwrapVariant(value)) {
1463
+ is Double -> formatJsNumber(unwrapped)
1464
+ else -> unwrapped.toString()
1465
+ }
1466
+
1467
+ /**
1468
+ * Renders a JS number the way JS itself — and therefore the iOS bridge —
1469
+ * renders it: `2` stays `"2"`, `2.5` stays `"2.5"`.
1470
+ *
1471
+ * Every JS number crosses Nitro as a [Double], so a JS `2` arrives as
1472
+ * `2.0`, and Kotlin's [Double.toString] spells that `"2.0"`. iOS hands the
1473
+ * same value to the SDK as a native number, which `NSJSONSerialization`
1474
+ * writes as `2`. The result was a cross-platform payload split on any
1475
+ * whole number — `"seats": "2.0"` on Android against `"seats": 2` on iOS —
1476
+ * which breaks dashboards and Composer rules that compare the two.
1477
+ * Dropping the trailing `.0` closes the *textual* half of that gap.
1478
+ *
1479
+ * It does not close the *type* half on the custom-event path: the SDK's
1480
+ * `logCustomEvent` chain is typed `HashMap<String, String>` end to end, so
1481
+ * an Android custom-event number is a JSON string (`"2"`) where iOS sends a
1482
+ * JSON number (`2`). Only `logSignal` carries native types on Android, and
1483
+ * that path deliberately does not come through here — see [toSignalPayload].
1484
+ *
1485
+ * Integral values are rendered through [Long] only below 2^53, which spans
1486
+ * every integer JS itself represents exactly; beyond that the [Double] form
1487
+ * is kept rather than inventing digits a `Long` round-trip would imply.
1488
+ * Non-finite values keep Kotlin's spelling (`"NaN"`, `"Infinity"`) — there
1489
+ * is no JSON representation to match, and stringifying is strictly safer
1490
+ * than throwing out of an analytics call.
1491
+ *
1492
+ * @param value The number to render.
1493
+ * @return Its string form, without a trailing `.0` for whole numbers.
1494
+ */
1495
+ internal fun formatJsNumber(value: Double): String {
1496
+ if (!value.isFinite()) {
1497
+ return value.toString()
1498
+ }
1499
+ if (value == Math.floor(value) && Math.abs(value) < 9007199254740992.0) {
1500
+ return value.toLong().toString()
1501
+ }
1502
+ return value.toString()
1503
+ }
1504
+
1203
1505
  /**
1204
1506
  * Converts a map of Variant_Boolean_String_Double to a HashMap<String?, String?>.
1205
1507
  *
1508
+ * Values are unwrapped before stringifying (see [variantToString]).
1509
+ *
1206
1510
  * @param values The map to be converted.
1207
1511
  * @return A HashMap<String?, String?> representation of the input map which library can use.
1208
1512
  */
@@ -1212,30 +1516,114 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1212
1516
  for (key in values.keys) {
1213
1517
  val value = values[key]
1214
1518
  if (value != null) {
1215
- map[key] = value.toString()
1519
+ map[key] = variantToString(value)
1216
1520
  }
1217
1521
  }
1218
1522
  return map
1219
1523
  }
1220
1524
 
1221
1525
  /**
1222
- * Converts a map of Variant_Boolean_String_Double to a HashMap<String?, String?>.
1526
+ * Converts an [AnyMap]-derived map into the payload `Connect.logSignal`
1527
+ * expects, rebuilding nested structures as [JSONObject] / [JSONArray].
1223
1528
  *
1224
- * @param values The map to be converted.
1225
- * @return A HashMap<String?, String?> representation of the input map which library can use.
1529
+ * The rebuild is mandatory, not cosmetic. The SDK serializes the signal
1530
+ * through EOCore's `JsonUtil.getHashValues`, which walks the top-level
1531
+ * entries and accumulates only `String`, `Boolean`, `Number` (from Connect
1532
+ * Android 11.0.24-beta), `JSONObject`, `JSONArray` and `ByteArray` —
1533
+ * anything else is **silently dropped**. So a nested `Map`/`List` handed
1534
+ * over as-is would vanish from the emitted signal without any error.
1535
+ * Converting here is what makes nested payloads survive the wire.
1536
+ *
1537
+ * `null` becomes [JSONObject.NULL] rather than a Kotlin `null`, which
1538
+ * `org.json` requires for an explicit JSON `null`.
1539
+ *
1540
+ * Version boundary — **top-level** numbers. `getHashValues` gained a
1541
+ * `Number` branch in Connect Android 11.0.24-beta and accumulates the boxed
1542
+ * value as-is, so a top-level number now reaches the wire. On earlier builds
1543
+ * its `instanceof` ladder had no such branch, the entry was skipped with no
1544
+ * error, and nothing here could rescue it. Numbers nested inside an object
1545
+ * or array were never affected — the enclosing [JSONObject]/[JSONArray] is
1546
+ * built here, so `org.json` serializes them normally — and iOS has always
1547
+ * carried top-level numbers. Both sides of the boundary sit inside the
1548
+ * `[11.0.11, 12.0.0)` range this bridge accepts, so an integration pinning
1549
+ * an older Connect version still sees the old behaviour; nesting a number
1550
+ * is portable across the whole range.
1551
+ *
1552
+ * A [JSONException] aborts the whole payload rather than escaping to the
1553
+ * caller. Non-finite numbers are the case that raises it: `org.json`
1554
+ * rejects them, and [toJsonValue] raises them explicitly so a top-level one
1555
+ * behaves like a nested one. Either way a JS `Infinity` or `NaN` would
1556
+ * otherwise throw straight out of `logSignal` and take the host app's call
1557
+ * site down — unacceptable for an analytics SDK, and a behaviour change
1558
+ * from the scalar-only bridge, which could not throw. Dropping the whole
1559
+ * payload also matches iOS, where a single non-finite value fails
1560
+ * `isValidJSONObject:` and the `signal` key is omitted entirely.
1561
+ *
1562
+ * @param values The map from [AnyMap.toHashMap].
1563
+ * @return A HashMap the SDK's signal serializer can consume, or an empty
1564
+ * map if the payload could not be represented as JSON.
1226
1565
  */
1227
1566
  // internal (not private) so the unit tests in src/test can exercise it.
1228
- internal fun convertToMapAny(values: Map<String, Variant_Boolean_String_Double>): java.util.HashMap<String?, Any?>? {
1229
- val map = HashMap<String?, Any?>()
1230
- for (key in values.keys) {
1231
- val value = values[key]
1232
- if (value != null) {
1233
- map[key] = value
1567
+ internal fun toSignalPayload(values: Map<String, Any?>): java.util.HashMap<String?, Any?> {
1568
+ val map = HashMap<String?, Any?>(values.size)
1569
+ try {
1570
+ for ((key, value) in values) {
1571
+ map[key] = toJsonValue(value)
1234
1572
  }
1573
+ } catch (e: JSONException) {
1574
+ Log.w(TAG, "[bridge] logSignal payload is not representable as JSON — dropping it: ${e.message}")
1575
+ return HashMap()
1235
1576
  }
1236
1577
  return map
1237
1578
  }
1238
1579
 
1580
+ /**
1581
+ * Recursive helper for [toSignalPayload]. Maps Kotlin containers onto their
1582
+ * `org.json` equivalents and leaves scalars alone.
1583
+ *
1584
+ * Nitro's JNI layer converts the whole tree to plain Java types before it
1585
+ * reaches Kotlin — a JS object becomes a `HashMap`, a JS array an
1586
+ * `ArrayList`, and scalars become `Double` / `Boolean` / `Long` / `String`
1587
+ * — so there are no `AnyValue` wrappers left to unwrap here. [List] is
1588
+ * therefore the branch a JS array actually takes; [Array] is handled too,
1589
+ * to guard against a future Nitro representation change.
1590
+ *
1591
+ * @param value A value from an [AnyMap]-derived container.
1592
+ * @return The `org.json`-compatible equivalent.
1593
+ */
1594
+ private fun toJsonValue(value: Any?): Any =
1595
+ when (value) {
1596
+ null -> JSONObject.NULL
1597
+ is Map<*, *> -> JSONObject().apply {
1598
+ for ((nestedKey, nestedValue) in value) {
1599
+ put(nestedKey.toString(), toJsonValue(nestedValue))
1600
+ }
1601
+ }
1602
+ is Array<*> -> JSONArray().apply {
1603
+ for (element in value) put(toJsonValue(element))
1604
+ }
1605
+ is List<*> -> JSONArray().apply {
1606
+ for (element in value) put(toJsonValue(element))
1607
+ }
1608
+ // Checked here rather than left to `org.json`. A non-finite number
1609
+ // nested in an object or array is rejected by that container's
1610
+ // `put`, but a TOP-LEVEL one is only ever handed to `HashMap.put`,
1611
+ // which accepts anything — so without this the payload would reach
1612
+ // the SDK, and what happened there would depend on the resolved
1613
+ // Connect version: before 11.0.24-beta it lost just that one key
1614
+ // while the nested case lost everything; from 11.0.24-beta the
1615
+ // SDK's own `Number` branch rejects it and drops the whole payload.
1616
+ // Raising it here keeps the two cases consistent across the
1617
+ // supported range and matches iOS, where one non-finite value fails
1618
+ // `isValidJSONObject:` for the entire signal.
1619
+ is Double -> if (value.isFinite()) {
1620
+ value
1621
+ } else {
1622
+ throw JSONException("non-finite number: $value")
1623
+ }
1624
+ else -> value
1625
+ }
1626
+
1239
1627
  /**
1240
1628
  * Gets the current activity from the ReactApplicationContext.
1241
1629
  *
@@ -1383,6 +1771,15 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1383
1771
  const val TAG = "AcousticConnectRN"
1384
1772
  const val DIALOG_CAPTURE_DELAY_MS = 500L // Configurable delay for dialog screenshot capture
1385
1773
 
1774
+ /** Key holding the per-screen capture delay, in milliseconds, inside a layout-config rule. */
1775
+ const val CAPTURE_LAYOUT_DELAY_KEY = "CaptureLayoutDelay"
1776
+
1777
+ /**
1778
+ * Delay applied when the layout config names none. Matches the value the
1779
+ * Connect SDK ships in its own `TealeafLayoutConfig.json`.
1780
+ */
1781
+ const val DEFAULT_CAPTURE_LAYOUT_DELAY_MS = 500
1782
+
1386
1783
  // Class probed at runtime to detect whether the connect-push-fcm
1387
1784
  // transport artifact was included in the build (i.e. automatic mode,
1388
1785
  // where Connect's own FirebaseMessagingService is the PushReceived
@@ -1390,5 +1787,28 @@ class HybridAcousticConnectRN : HybridAcousticConnectRNSpec(),
1390
1787
  // by the connect-push-fcm artifact.
1391
1788
  private const val CONNECT_PUSH_FCM_PROBE_CLASS =
1392
1789
  "com.acoustic.connect.android.connectmod.push.services.fcm.FCMPushService"
1790
+
1791
+ /**
1792
+ * Default `additionalParameters` for an identity signal, matched to the
1793
+ * signal type the bridge will actually send.
1794
+ *
1795
+ * Connect's signal schema requires a *method* attribute on identity
1796
+ * signals, and the required key differs per type: `loggedIn` requires
1797
+ * `loginMethod`, `accountRegistered` requires `registrationMethod`.
1798
+ * Supplying the wrong one fails schema validation and the signal is
1799
+ * discarded, while [Connect.logIdentificationEvent] still reports
1800
+ * success — so the caller sees nothing wrong. Before this mapping
1801
+ * existed the bridge paired its `loggedIn` default with
1802
+ * `registrationMethod`, which meant every defaulted identity call was
1803
+ * silently dropped.
1804
+ *
1805
+ * Only consulted when the caller omits `additionalParameters`
1806
+ * entirely; an explicitly-provided map is passed through untouched.
1807
+ */
1808
+ internal fun defaultIdentityParameters(signalType: String): Map<String, String> =
1809
+ when (signalType) {
1810
+ "loggedIn" -> mapOf("loginMethod" to "email")
1811
+ else -> mapOf("registrationMethod" to "email")
1812
+ }
1393
1813
  }
1394
1814
  }