@react-native-ohos/react-native-ble-plx 3.5.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +202 -0
  2. package/README.OpenSource +11 -0
  3. package/README.md +9 -0
  4. package/app.plugin.js +1 -0
  5. package/harmony/rn_bleplx/BuildProfile.ets +9 -0
  6. package/harmony/rn_bleplx/build-profile.json5 +8 -0
  7. package/harmony/rn_bleplx/hvigorfile.ts +6 -0
  8. package/harmony/rn_bleplx/index.ets +5 -0
  9. package/harmony/rn_bleplx/obfuscation-rules.txt +18 -0
  10. package/harmony/rn_bleplx/oh-package.json5 +13 -0
  11. package/harmony/rn_bleplx/src/main/cpp/CMakeLists.txt +9 -0
  12. package/harmony/rn_bleplx/src/main/cpp/generated/BlePlx.cpp +64 -0
  13. package/harmony/rn_bleplx/src/main/cpp/generated/BlePlx.h +21 -0
  14. package/harmony/rn_bleplx/src/main/cpp/generated/BlePlxRNOHGeneratedPackage.h +76 -0
  15. package/harmony/rn_bleplx/src/main/ets/BleDevice.ts +79 -0
  16. package/harmony/rn_bleplx/src/main/ets/BleModule.ts +1208 -0
  17. package/harmony/rn_bleplx/src/main/ets/BlePlxInterface.ts +7 -0
  18. package/harmony/rn_bleplx/src/main/ets/BlePlxModule.ts +226 -0
  19. package/harmony/rn_bleplx/src/main/ets/BlePlxPackage.ts +26 -0
  20. package/harmony/rn_bleplx/src/main/ets/Characteristic.ts +159 -0
  21. package/harmony/rn_bleplx/src/main/ets/CommonConstants.ts +10 -0
  22. package/harmony/rn_bleplx/src/main/ets/Descriptor.ts +123 -0
  23. package/harmony/rn_bleplx/src/main/ets/Service.ts +65 -0
  24. package/harmony/rn_bleplx/src/main/ets/common/BleError.ts +70 -0
  25. package/harmony/rn_bleplx/src/main/ets/common/BleErrorToJsObjectConverter.ts +43 -0
  26. package/harmony/rn_bleplx/src/main/ets/common/BleEvent.ts +13 -0
  27. package/harmony/rn_bleplx/src/main/ets/common/BleUtils.ts +66 -0
  28. package/harmony/rn_bleplx/src/main/ets/common/IdGenerator.ts +29 -0
  29. package/harmony/rn_bleplx/src/main/ets/common/IdGeneratorKey.ts +50 -0
  30. package/harmony/rn_bleplx/src/main/ets/common/InstanceIdGenerator.ts +17 -0
  31. package/harmony/rn_bleplx/src/main/ets/common/Logger.ts +64 -0
  32. package/harmony/rn_bleplx/src/main/ets/common/PermissionHandler.ts +78 -0
  33. package/harmony/rn_bleplx/src/main/ets/common/ServiceFactory.ts +17 -0
  34. package/harmony/rn_bleplx/src/main/ets/generated/components/ts.ts +8 -0
  35. package/harmony/rn_bleplx/src/main/ets/generated/index.ets +8 -0
  36. package/harmony/rn_bleplx/src/main/ets/generated/ts.ts +9 -0
  37. package/harmony/rn_bleplx/src/main/ets/generated/turboModules/BlePlx.ts +105 -0
  38. package/harmony/rn_bleplx/src/main/ets/generated/turboModules/ts.ts +8 -0
  39. package/harmony/rn_bleplx/src/main/module.json5 +7 -0
  40. package/harmony/rn_bleplx/ts.ts +6 -0
  41. package/harmony/rn_bleplx.har +0 -0
  42. package/package.json +181 -0
  43. package/src/BleError.js +555 -0
  44. package/src/BleManager.js +1324 -0
  45. package/src/BleModule.js +857 -0
  46. package/src/Characteristic.js +180 -0
  47. package/src/Descriptor.js +83 -0
  48. package/src/Device.js +378 -0
  49. package/src/NativeBlePlx.ts +101 -0
  50. package/src/Service.js +204 -0
  51. package/src/TypeDefinition.js +365 -0
  52. package/src/Utils.js +29 -0
  53. package/src/index.d.ts +2126 -0
  54. package/src/index.js +20 -0
@@ -0,0 +1,1324 @@
1
+ // @flow
2
+ 'use strict'
3
+
4
+ import { Device } from './Device'
5
+ import { Service } from './Service'
6
+ import { Characteristic } from './Characteristic'
7
+ import { Descriptor } from './Descriptor'
8
+ import { State, LogLevel, ConnectionPriority } from './TypeDefinition'
9
+ // import { BleModule, EventEmitter } from './BleModule'
10
+ import { EventEmitter } from './BleModule'
11
+ import BleModule from './NativeBlePlx'
12
+ import {
13
+ parseBleError,
14
+ BleError,
15
+ BleErrorCode,
16
+ BleErrorCodeMessage,
17
+ BleATTErrorCode,
18
+ BleAndroidErrorCode,
19
+ BleIOSErrorCode
20
+ } from './BleError'
21
+ import type { NativeDevice, NativeCharacteristic, NativeDescriptor, NativeBleRestoredState } from './BleModule'
22
+ import type {
23
+ BleErrorCodeMessageMapping,
24
+ Subscription,
25
+ DeviceId,
26
+ Identifier,
27
+ UUID,
28
+ TransactionId,
29
+ CharacteristicSubscriptionType,
30
+ Base64,
31
+ ScanOptions,
32
+ ConnectionOptions,
33
+ BleManagerOptions
34
+ } from './TypeDefinition'
35
+ import { isIOS } from './Utils'
36
+ import { Platform } from 'react-native'
37
+
38
+ const enableDisableDeprecatedMessage =
39
+ 'react-native-ble-plx: The enable and disable feature is no longer supported. In Android SDK 31+ there were major changes in permissions, which may cause problems with these functions, and in SDK 33+ they were completely removed.'
40
+
41
+ /**
42
+ *
43
+ * BleManager is an entry point for react-native-ble-plx library. It provides all means to discover and work with
44
+ * {@link Device} instances. It should be initialized only once with `new` keyword and method
45
+ * {@link #blemanagerdestroy|destroy()} should be called on its instance when user wants to deallocate all resources.
46
+ *
47
+ * In case you want to properly support Background Mode, you should provide `restoreStateIdentifier` and
48
+ * `restoreStateFunction` in {@link BleManagerOptions}.
49
+ *
50
+ * @example
51
+ * const manager = new BleManager();
52
+ * // ... work with BLE manager ...
53
+ * manager.destroy();
54
+ */
55
+ export class BleManager {
56
+ // Scan subscriptions
57
+ // $FlowIssue[missing-type-arg]
58
+ _scanEventSubscription: ?EventEmitter
59
+ // Listening to BleModule events
60
+ // $FlowIssue[missing-type-arg]
61
+ _eventEmitter: EventEmitter
62
+ // Unique identifier used to create internal transactionIds
63
+ _uniqueId: number
64
+ // Map of active promises with functions to forcibly cancel them
65
+ _activePromises: { [id: string]: (error: BleError) => void }
66
+ // Map of active subscriptions
67
+ _activeSubscriptions: { [id: string]: Subscription }
68
+
69
+ // Map of error codes to error messages
70
+ _errorCodesToMessagesMapping: BleErrorCodeMessageMapping
71
+
72
+ static sharedInstance: BleManager | null = null
73
+
74
+ /**
75
+ * Creates an instance of {@link BleManager}.
76
+ * It will return already created instance if it was created before.
77
+ * If you want to create a new instance to for example use different options, you have to call {@link #blemanagerdestroy|destroy()} on the previous one.
78
+ */
79
+ constructor(options: BleManagerOptions = {}) {
80
+ if (BleManager.sharedInstance !== null) {
81
+ // $FlowFixMe - Constructor returns shared instance for singleton pattern
82
+ return BleManager.sharedInstance
83
+ }
84
+
85
+ this._eventEmitter = new EventEmitter(BleModule)
86
+ this._uniqueId = 0
87
+ this._activePromises = {}
88
+ this._activeSubscriptions = {}
89
+
90
+ const restoreStateFunction = options.restoreStateFunction
91
+ if (restoreStateFunction != null && options.restoreStateIdentifier != null) {
92
+ // $FlowIssue[prop-missing]
93
+ this._activeSubscriptions[this._nextUniqueID()] = this._eventEmitter.addListener(
94
+ Platform.OS === 'harmony' ? 'RestoreStateEvent' : BleModule.RestoreStateEvent,
95
+ (nativeRestoredState: NativeBleRestoredState) => {
96
+ if (nativeRestoredState == null) {
97
+ restoreStateFunction(null)
98
+ return
99
+ }
100
+ restoreStateFunction({
101
+ connectedPeripherals: nativeRestoredState.connectedPeripherals.map(
102
+ nativeDevice => new Device(nativeDevice, this)
103
+ )
104
+ })
105
+ }
106
+ )
107
+ }
108
+
109
+ this._errorCodesToMessagesMapping = options.errorCodesToMessagesMapping
110
+ ? options.errorCodesToMessagesMapping
111
+ : BleErrorCodeMessage
112
+
113
+ BleModule.createClient(options.restoreStateIdentifier || null)
114
+ BleManager.sharedInstance = this
115
+ }
116
+
117
+ /**
118
+ * Destroys all promises which are in progress.
119
+ * @private
120
+ */
121
+ _destroyPromises() {
122
+ const destroyedError = new BleError(
123
+ {
124
+ errorCode: BleErrorCode.BluetoothManagerDestroyed,
125
+ attErrorCode: (null: ?$Values<typeof BleATTErrorCode>),
126
+ iosErrorCode: (null: ?$Values<typeof BleIOSErrorCode>),
127
+ androidErrorCode: (null: ?$Values<typeof BleAndroidErrorCode>),
128
+ reason: (null: ?string)
129
+ },
130
+ this._errorCodesToMessagesMapping
131
+ )
132
+ for (const id in this._activePromises) {
133
+ this._activePromises[id](destroyedError)
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Destroys all subscriptions.
139
+ * @private
140
+ */
141
+ _destroySubscriptions() {
142
+ for (const id in this._activeSubscriptions) {
143
+ this._activeSubscriptions[id].remove()
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Destroys {@link BleManager} instance. A new instance needs to be created to continue working with
149
+ * this library. All operations which were in progress completes with
150
+ * @returns {Promise<void>} Promise may return an error when the function cannot be called.
151
+ * {@link #bleerrorcodebluetoothmanagerdestroyed|BluetoothManagerDestroyed} error code.
152
+ */
153
+ async destroy(): Promise<void> {
154
+ const response = await this._callPromise(BleModule.destroyClient())
155
+
156
+ // Unsubscribe from any subscriptions
157
+ if (this._scanEventSubscription != null) {
158
+ this._scanEventSubscription.remove()
159
+ this._scanEventSubscription = null
160
+ }
161
+ this._destroySubscriptions()
162
+
163
+ if (BleManager.sharedInstance) {
164
+ BleManager.sharedInstance = null
165
+ }
166
+
167
+ // Destroy all promises
168
+ this._destroyPromises()
169
+
170
+ return response
171
+ }
172
+
173
+ /**
174
+ * Generates new unique identifier to be used internally.
175
+ *
176
+ * @returns {string} New identifier.
177
+ * @private
178
+ */
179
+ _nextUniqueID(): string {
180
+ this._uniqueId += 1
181
+ return this._uniqueId.toString()
182
+ }
183
+
184
+ /**
185
+ * Calls promise and checks if it completed successfully
186
+ *
187
+ * @param {Promise<T>} promise Promise to be called
188
+ * @returns {Promise<T>} Value of called promise.
189
+ * @private
190
+ */
191
+ async _callPromise<T>(promise: Promise<T>): Promise<T> {
192
+ const id = this._nextUniqueID()
193
+ try {
194
+ const destroyPromise = new Promise((resolve, reject) => {
195
+ this._activePromises[id] = reject
196
+ })
197
+ const value = await Promise.race([destroyPromise, promise])
198
+ delete this._activePromises[id]
199
+ // $FlowIssue[incompatible-return]
200
+ return value
201
+ } catch (error) {
202
+ delete this._activePromises[id]
203
+ throw parseBleError(error.message, this._errorCodesToMessagesMapping)
204
+ }
205
+ }
206
+
207
+ // Mark: Common ------------------------------------------------------------------------------------------------------
208
+
209
+ /**
210
+ * Sets new log level for native module's logging mechanism.
211
+ * @param {LogLevel} logLevel New log level to be set.
212
+ * @returns {Promise<LogLevel>} Current log level.
213
+ */
214
+ setLogLevel(logLevel: $Keys<typeof LogLevel>): Promise<$Keys<typeof LogLevel> | void> {
215
+ return this._callPromise(BleModule.setLogLevel(logLevel))
216
+ }
217
+
218
+ /**
219
+ * Get current log level for native module's logging mechanism.
220
+ * @returns {Promise<LogLevel>} Current log level.
221
+ */
222
+ logLevel(): Promise<$Keys<typeof LogLevel>> {
223
+ return this._callPromise(BleModule.logLevel())
224
+ }
225
+
226
+ /**
227
+ * Cancels pending transaction.
228
+ *
229
+ * Few operations such as monitoring characteristic's value changes can be cancelled by a user. Basically every API
230
+ * entry which accepts `transactionId` allows to call `cancelTransaction` function. When cancelled operation is a
231
+ * promise or a callback which registers errors, {@link #bleerror|BleError} with error code
232
+ * {@link #bleerrorcodeoperationcancelled|OperationCancelled} will be emitted in that case. Cancelling transaction
233
+ * which doesn't exist is ignored.
234
+ *
235
+ * @example
236
+ * const transactionId = 'monitor_battery';
237
+ *
238
+ * // Monitor battery notifications
239
+ * manager.monitorCharacteristicForDevice(
240
+ * device.id, '180F', '2A19',
241
+ * (error, characteristic) => {
242
+ * // Handle battery level changes...
243
+ * }, transactionId);
244
+ *
245
+ * // Cancel after specified amount of time
246
+ * setTimeout(() => manager.cancelTransaction(transactionId), 2000);
247
+ *
248
+ * @param {TransactionId} transactionId Id of pending transactions.
249
+ * @returns {Promise<void>}
250
+ */
251
+ cancelTransaction(transactionId: TransactionId): Promise<void> {
252
+ return this._callPromise(BleModule.cancelTransaction(transactionId))
253
+ }
254
+
255
+ // Mark: Monitoring state --------------------------------------------------------------------------------------------
256
+
257
+ /**
258
+ * Enable Bluetooth. This function blocks until BLE is in PoweredOn state. [Android only]
259
+ *
260
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
261
+ * @returns {Promise<BleManager>} Promise completes when state transition was successful.
262
+ */
263
+ async enable(transactionId: ?TransactionId): Promise<BleManager> {
264
+ if (!transactionId) {
265
+ transactionId = this._nextUniqueID()
266
+ }
267
+ await this._callPromise(BleModule.enable(transactionId))
268
+ return this
269
+ }
270
+
271
+ /**
272
+ * Deprecated
273
+ * Disable Bluetooth. This function blocks until BLE is in PoweredOff state. [Android only]
274
+ *
275
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
276
+ * @returns {Promise<BleManager>} Promise completes when state transition was successful.
277
+ */
278
+ async disable(transactionId: ?TransactionId): Promise<BleManager> {
279
+ console.warn(enableDisableDeprecatedMessage)
280
+ if (!transactionId) {
281
+ transactionId = this._nextUniqueID()
282
+ }
283
+ await this._callPromise(BleModule.disable(transactionId))
284
+ return this
285
+ }
286
+
287
+ /**
288
+ * Current, global {@link State} of a {@link BleManager}. All APIs are working only when active state
289
+ * is "PoweredOn".
290
+ *
291
+ * @returns {Promise<State>} Promise which emits current state of BleManager.
292
+ */
293
+ state(): Promise<$Keys<typeof State>> {
294
+ return this._callPromise(BleModule.state())
295
+ }
296
+
297
+ /**
298
+ * Notifies about {@link State} changes of a {@link BleManager}.
299
+ *
300
+ * @example
301
+ * const subscription = this.manager.onStateChange((state) => {
302
+ * if (state === 'PoweredOn') {
303
+ * this.scanAndConnect();
304
+ * subscription.remove();
305
+ * }
306
+ * }, true);
307
+ *
308
+ * @param {function(newState: State)} listener Callback which emits state changes of BLE Manager.
309
+ * Look at {@link State} for possible values.
310
+ * @param {boolean} [emitCurrentState=false] If true, current state will be emitted as well. Defaults to false.
311
+ *
312
+ * @returns {Subscription} Subscription on which `remove()` function can be called to unsubscribe.
313
+ */
314
+ onStateChange(
315
+ listener: (newState: $Keys<typeof State>) => void,
316
+ emitCurrentState: boolean = false
317
+ ): Subscription {
318
+ const subscription: Subscription = this._eventEmitter.addListener(Platform.OS === 'harmony' ? 'StateChangeEvent' : BleModule.StateChangeEvent, listener)
319
+ const id = this._nextUniqueID()
320
+ var wrappedSubscription: Subscription
321
+
322
+ if (emitCurrentState) {
323
+ var cancelled = false
324
+ this._callPromise(this.state()).then(currentState => {
325
+ if (!cancelled) {
326
+ listener(currentState)
327
+ }
328
+ })
329
+
330
+ wrappedSubscription = {
331
+ remove: () => {
332
+ if (this._activeSubscriptions[id] != null) {
333
+ cancelled = true
334
+ delete this._activeSubscriptions[id]
335
+ subscription.remove()
336
+ }
337
+ }
338
+ }
339
+ } else {
340
+ wrappedSubscription = {
341
+ remove: () => {
342
+ if (this._activeSubscriptions[id] != null) {
343
+ delete this._activeSubscriptions[id]
344
+ subscription.remove()
345
+ }
346
+ }
347
+ }
348
+ }
349
+
350
+ this._activeSubscriptions[id] = wrappedSubscription
351
+ return wrappedSubscription
352
+ }
353
+
354
+ // Mark: Scanning ----------------------------------------------------------------------------------------------------
355
+
356
+ /**
357
+ * Starts device scanning. When previous scan is in progress it will be stopped before executing this command.
358
+ *
359
+ * @param {?Array<UUID>} UUIDs Array of strings containing {@link UUID}s of {@link Service}s which are registered in
360
+ * scanned {@link Device}. If `null` is passed, all available {@link Device}s will be scanned.
361
+ * @param {?ScanOptions} options Optional configuration for scanning operation.
362
+ * @param {function(error: ?BleError, scannedDevice: ?Device)} listener Function which will be called for every scanned
363
+ * @returns {Promise<void>} Promise may return an error when the function cannot be called.
364
+ * {@link Device} (devices may be scanned multiple times). It's first argument is potential {@link Error} which is set
365
+ * to non `null` value when scanning failed. You have to start scanning process again if that happens. Second argument
366
+ * is a scanned {@link Device}.
367
+ * @returns {Promise<void>} the promise may be rejected if the operation is impossible to perform.
368
+ */
369
+ async startDeviceScan(
370
+ UUIDs: ?Array<UUID>,
371
+ options: ?ScanOptions,
372
+ listener: (error: ?BleError, scannedDevice: ?Device) => Promise<void>
373
+ ): Promise<void> {
374
+ const scanListener = ([error, nativeDevice]: [?string, ?NativeDevice]) => {
375
+ listener(
376
+ error ? parseBleError(error, this._errorCodesToMessagesMapping) : null,
377
+ nativeDevice ? new Device(nativeDevice, this) : null
378
+ )
379
+ }
380
+ // $FlowFixMe: Flow cannot deduce EmitterSubscription type.
381
+ this._scanEventSubscription = this._eventEmitter.addListener(Platform.OS === 'harmony' ? 'ScanEvent' : BleModule.ScanEvent, scanListener)
382
+
383
+ return this._callPromise(BleModule.startDeviceScan(UUIDs, options))
384
+ }
385
+
386
+ /**
387
+ * Stops {@link Device} scan if in progress.
388
+ * @returns {Promise<void>} the promise may be rejected if the operation is impossible to perform.
389
+ */
390
+ stopDeviceScan (): Promise<void> {
391
+ if (this._scanEventSubscription != null) {
392
+ this._scanEventSubscription.remove()
393
+ this._scanEventSubscription = null
394
+ }
395
+
396
+ return this._callPromise(BleModule.stopDeviceScan())
397
+ }
398
+
399
+ /**
400
+ * Request a connection parameter update. This functions may update connection parameters on Android API level 21 or
401
+ * above.
402
+ *
403
+ * @param {DeviceId} deviceIdentifier Device identifier.
404
+ * @param {ConnectionPriority} connectionPriority: Connection priority.
405
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation.
406
+ * @returns {Promise<Device>} Connected device.
407
+ */
408
+ async requestConnectionPriorityForDevice(
409
+ deviceIdentifier: DeviceId,
410
+ connectionPriority: $Values<typeof ConnectionPriority>,
411
+ transactionId: ?TransactionId
412
+ ): Promise<Device> {
413
+ if (!transactionId) {
414
+ transactionId = this._nextUniqueID()
415
+ }
416
+ const nativeDevice = await this._callPromise(
417
+ BleModule.requestConnectionPriorityForDevice(deviceIdentifier, connectionPriority, transactionId)
418
+ )
419
+ const services = await this._callPromise(BleModule.servicesForDevice(deviceIdentifier))
420
+ const serviceUUIDs = (services || []).map(service => service.uuid)
421
+
422
+ // $FlowFixMe
423
+ const device = {
424
+ ...nativeDevice,
425
+ serviceUUIDs
426
+ }
427
+ return new Device(device, this)
428
+ }
429
+
430
+ /**
431
+ * Reads RSSI for connected device.
432
+ *
433
+ * @param {DeviceId} deviceIdentifier Device identifier.
434
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
435
+ * @returns {Promise<Device>} Connected device with updated RSSI value.
436
+ */
437
+ async readRSSIForDevice(deviceIdentifier: DeviceId, transactionId: ?TransactionId): Promise<Device> {
438
+ if (!transactionId) {
439
+ transactionId = this._nextUniqueID()
440
+ }
441
+ const nativeDevice = await this._callPromise(BleModule.readRSSIForDevice(deviceIdentifier, transactionId))
442
+ return new Device(nativeDevice, this)
443
+ }
444
+
445
+ /**
446
+ * Request new MTU value for this device. This function currently is not doing anything
447
+ * on iOS platform as MTU exchange is done automatically. Since Android 14,
448
+ * mtu management has been changed, more information can be found at the link:
449
+ * https://developer.android.com/about/versions/14/behavior-changes-all#mtu-set-to-517
450
+ * @param {DeviceId} deviceIdentifier Device identifier.
451
+ * @param {number} mtu New MTU to negotiate.
452
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
453
+ * @returns {Promise<Device>} Device with updated MTU size. Default value is 23 (517 since Android 14)..
454
+ */
455
+ async requestMTUForDevice(deviceIdentifier: DeviceId, mtu: number, transactionId: ?TransactionId): Promise<Device> {
456
+ if (!transactionId) {
457
+ transactionId = this._nextUniqueID()
458
+ }
459
+ const nativeDevice = await this._callPromise(BleModule.requestMTUForDevice(deviceIdentifier, mtu, transactionId))
460
+ return new Device(nativeDevice, this)
461
+ }
462
+
463
+ // Mark: Connection management ---------------------------------------------------------------------------------------
464
+
465
+ /**
466
+ * Returns a list of known devices by their identifiers.
467
+ * @param {Array<DeviceId>} deviceIdentifiers List of device identifiers.
468
+ * @returns {Promise<Array<Device>>} List of known devices by their identifiers.
469
+ */
470
+ async devices(deviceIdentifiers: Array<DeviceId>): Promise<Array<Device>> {
471
+ const nativeDevices = await this._callPromise(BleModule.devices(deviceIdentifiers))
472
+ return nativeDevices.map((nativeDevice: NativeDevice) => {
473
+ return new Device(nativeDevice, this)
474
+ })
475
+ }
476
+
477
+ /**
478
+ * Returns a list of the peripherals (containing any of the specified services) currently connected to the system
479
+ * which have discovered services. Returned devices **may not be connected** to your application. Make sure to check
480
+ * if that's the case with function {@link #blemanagerisdeviceconnected|isDeviceConnected}.
481
+ * @param {Array<UUID>} serviceUUIDs List of service UUIDs. Device must contain at least one of them to be listed.
482
+ * @returns {Promise<Array<Device>>} List of known devices with discovered services as stated in the parameter.
483
+ */
484
+ async connectedDevices(serviceUUIDs: Array<UUID>): Promise<Array<Device>> {
485
+ const nativeDevices = await this._callPromise(BleModule.connectedDevices(serviceUUIDs))
486
+ return nativeDevices.map((nativeDevice: NativeDevice) => {
487
+ return new Device(nativeDevice, this)
488
+ })
489
+ }
490
+
491
+ // Mark: Connection management ---------------------------------------------------------------------------------------
492
+
493
+ /**
494
+ * Connects to {@link Device} with provided ID.
495
+ *
496
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
497
+ * @param {?ConnectionOptions} options Platform specific options for connection establishment.
498
+ * @returns {Promise<Device>} Connected {@link Device} object if successful.
499
+ */
500
+ async connectToDevice(deviceIdentifier: DeviceId, options: ?ConnectionOptions): Promise<Device> {
501
+ if (Platform.OS === 'android' && (await this.isDeviceConnected(deviceIdentifier))) {
502
+ await this.cancelDeviceConnection(deviceIdentifier)
503
+ }
504
+ const nativeDevice = await this._callPromise(BleModule.connectToDevice(deviceIdentifier, options))
505
+ return new Device(nativeDevice, this)
506
+ }
507
+
508
+ /**
509
+ * Disconnects from {@link Device} if it's connected or cancels pending connection.
510
+ *
511
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier to be closed.
512
+ * @returns {Promise<Device>} Returns closed {@link Device} when operation is successful.
513
+ */
514
+ async cancelDeviceConnection(deviceIdentifier: DeviceId): Promise<Device> {
515
+ const nativeDevice = await this._callPromise(BleModule.cancelDeviceConnection(deviceIdentifier))
516
+ return new Device(nativeDevice, this)
517
+ }
518
+
519
+ /**
520
+ * Monitors if {@link Device} was disconnected due to any errors or connection problems.
521
+ *
522
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier to be monitored.
523
+ * @param {function(error: ?BleError, device: Device)} listener - callback returning error as a reason of disconnection
524
+ * if available and {@link Device} object. If an error is null, that means the connection was terminated by
525
+ * {@link #blemanagercanceldeviceconnection|bleManager.cancelDeviceConnection()} call.
526
+ * @returns {Subscription} Subscription on which `remove()` function can be called to unsubscribe.
527
+ */
528
+ onDeviceDisconnected(deviceIdentifier: DeviceId, listener: (error: ?BleError, device: Device) => void): Subscription {
529
+ const disconnectionListener = ([error, nativeDevice]: [?string, NativeDevice]) => {
530
+ if (deviceIdentifier !== nativeDevice.id) {
531
+ return
532
+ }
533
+ listener(error ? parseBleError(error, this._errorCodesToMessagesMapping) : null, new Device(nativeDevice, this))
534
+ }
535
+
536
+ const subscription: Subscription = this._eventEmitter.addListener(
537
+ Platform.OS === 'harmony' ? 'DisconnectionEvent' : BleModule.DisconnectionEvent,
538
+ disconnectionListener
539
+ )
540
+
541
+ const id = this._nextUniqueID()
542
+ const wrappedSubscription = {
543
+ remove: () => {
544
+ if (this._activeSubscriptions[id] != null) {
545
+ delete this._activeSubscriptions[id]
546
+ subscription.remove()
547
+ }
548
+ }
549
+ }
550
+ this._activeSubscriptions[id] = wrappedSubscription
551
+ return wrappedSubscription
552
+ }
553
+
554
+ /**
555
+ * Check connection state of a {@link Device}.
556
+ *
557
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
558
+ * @returns {Promise<boolean>} Promise which emits `true` if device is connected, and `false` otherwise.
559
+ */
560
+ isDeviceConnected(deviceIdentifier: DeviceId): Promise<boolean> {
561
+ return this._callPromise(BleModule.isDeviceConnected(deviceIdentifier))
562
+ }
563
+
564
+ // Mark: Discovery ---------------------------------------------------------------------------------------------------
565
+
566
+ /**
567
+ * Discovers all {@link Service}s, {@link Characteristic}s and {@link Descriptor}s for {@link Device}.
568
+ *
569
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
570
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
571
+ * @returns {Promise<Device>} Promise which emits {@link Device} object if all available services and
572
+ * characteristics have been discovered.
573
+ */
574
+ async discoverAllServicesAndCharacteristicsForDevice(
575
+ deviceIdentifier: DeviceId,
576
+ transactionId: ?TransactionId
577
+ ): Promise<Device> {
578
+ if (!transactionId) {
579
+ transactionId = this._nextUniqueID()
580
+ }
581
+ const nativeDevice = await this._callPromise(
582
+ BleModule.discoverAllServicesAndCharacteristicsForDevice(deviceIdentifier, transactionId)
583
+ )
584
+ return new Device(nativeDevice, this)
585
+ }
586
+
587
+ // Mark: Service and characteristic getters --------------------------------------------------------------------------
588
+
589
+ /**
590
+ * List of discovered {@link Service}s for {@link Device}.
591
+ *
592
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
593
+ * @returns {Promise<Array<Service>>} Promise which emits array of {@link Service} objects which are discovered for a
594
+ * {@link Device}.
595
+ */
596
+ async servicesForDevice(deviceIdentifier: DeviceId): Promise<Array<Service>> {
597
+ const services = await this._callPromise(BleModule.servicesForDevice(deviceIdentifier))
598
+ return services.map(nativeService => {
599
+ return new Service(nativeService, this)
600
+ })
601
+ }
602
+
603
+ /**
604
+ * List of discovered {@link Characteristic}s for given {@link Device} and {@link Service}.
605
+ *
606
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
607
+ * @param {UUID} serviceUUID {@link Service} UUID.
608
+ * @returns {Promise<Array<Characteristic>>} Promise which emits array of {@link Characteristic} objects which are
609
+ * discovered for a {@link Device} in specified {@link Service}.
610
+ */
611
+ characteristicsForDevice(deviceIdentifier: DeviceId, serviceUUID: UUID): Promise<Array<Characteristic>> {
612
+ return this._handleCharacteristics(BleModule.characteristicsForDevice(deviceIdentifier, serviceUUID))
613
+ }
614
+
615
+ /**
616
+ * List of discovered {@link Characteristic}s for unique {@link Service}.
617
+ *
618
+ * @param {Identifier} serviceIdentifier {@link Service} ID.
619
+ * @returns {Promise<Array<Characteristic>>} Promise which emits array of {@link Characteristic} objects which are
620
+ * discovered in unique {@link Service}.
621
+ * @private
622
+ */
623
+ _characteristicsForService(serviceIdentifier: Identifier): Promise<Array<Characteristic>> {
624
+ return this._handleCharacteristics(BleModule.characteristicsForService(serviceIdentifier))
625
+ }
626
+
627
+ /**
628
+ * Common code for handling NativeCharacteristic fetches.
629
+ *
630
+ * @param {Promise<Array<NativeCharacteristic>>} characteristicsPromise Native characteristics.
631
+ * @returns {Promise<Array<Characteristic>>} Promise which emits array of {@link Characteristic} objects which are
632
+ * discovered in unique {@link Service}.
633
+ * @private
634
+ */
635
+ async _handleCharacteristics(
636
+ characteristicsPromise: Promise<Array<NativeCharacteristic>>
637
+ ): Promise<Array<Characteristic>> {
638
+ const characteristics = await this._callPromise(characteristicsPromise)
639
+ return characteristics.map(nativeCharacteristic => {
640
+ return new Characteristic(nativeCharacteristic, this)
641
+ })
642
+ }
643
+
644
+ /**
645
+ * List of discovered {@link Descriptor}s for given {@link Device}, {@link Service} and {@link Characteristic}.
646
+ *
647
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
648
+ * @param {UUID} serviceUUID {@link Service} UUID.
649
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
650
+ * @returns {Promise<Array<Descriptor>>} Promise which emits array of {@link Descriptor} objects which are
651
+ * discovered for a {@link Device}, {@link Service} in specified {@link Characteristic}.
652
+ */
653
+ descriptorsForDevice(
654
+ deviceIdentifier: DeviceId,
655
+ serviceUUID: UUID,
656
+ characteristicUUID: UUID
657
+ ): Promise<Array<Descriptor>> {
658
+ return this._handleDescriptors(BleModule.descriptorsForDevice(deviceIdentifier, serviceUUID, characteristicUUID))
659
+ }
660
+
661
+ /**
662
+ * List of discovered {@link Descriptor}s for given {@link Service} and {@link Characteristic}.
663
+ *
664
+ * @param {Identifier} serviceIdentifier {@link Service} identifier.
665
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
666
+ * @returns {Promise<Array<Descriptor>>} Promise which emits array of {@link Descriptor} objects which are
667
+ * discovered for a {@link Service} in specified {@link Characteristic}.
668
+ * @private
669
+ */
670
+ _descriptorsForService(serviceIdentifier: Identifier, characteristicUUID: UUID): Promise<Array<Descriptor>> {
671
+ return this._handleDescriptors(BleModule.descriptorsForService(serviceIdentifier, characteristicUUID))
672
+ }
673
+
674
+ /**
675
+ * List of discovered {@link Descriptor}s for given {@link Characteristic}.
676
+ *
677
+ * @param {Identifier} characteristicIdentifier {@link Characteristic} identifier.
678
+ * @returns {Promise<Array<Descriptor>>} Promise which emits array of {@link Descriptor} objects which are
679
+ * discovered in specified {@link Characteristic}.
680
+ * @private
681
+ */
682
+ _descriptorsForCharacteristic(characteristicIdentifier: Identifier): Promise<Array<Descriptor>> {
683
+ return this._handleDescriptors(BleModule.descriptorsForCharacteristic(characteristicIdentifier))
684
+ }
685
+
686
+ /**
687
+ * Common code for handling NativeDescriptor fetches.
688
+ * @param {Promise<Array<NativeDescriptor>>} descriptorsPromise Native descriptors.
689
+ * @returns {Promise<Array<Descriptor>>} Promise which emits array of {@link Descriptor} objects which are
690
+ * discovered in unique {@link Characteristic}.
691
+ * @private
692
+ */
693
+ async _handleDescriptors(descriptorsPromise: Promise<Array<NativeDescriptor>>): Promise<Array<Descriptor>> {
694
+ const descriptors = await this._callPromise(descriptorsPromise)
695
+ return descriptors.map(nativeDescriptor => {
696
+ return new Descriptor(nativeDescriptor, this)
697
+ })
698
+ }
699
+
700
+ // Mark: Characteristics operations ----------------------------------------------------------------------------------
701
+
702
+ /**
703
+ * Read {@link Characteristic} value.
704
+ *
705
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
706
+ * @param {UUID} serviceUUID {@link Service} UUID.
707
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
708
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
709
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
710
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified
711
+ * UUID paths. Latest value of {@link Characteristic} will be stored inside returned object.
712
+ */
713
+ async readCharacteristicForDevice(
714
+ deviceIdentifier: DeviceId,
715
+ serviceUUID: UUID,
716
+ characteristicUUID: UUID,
717
+ transactionId: ?TransactionId
718
+ ): Promise<Characteristic> {
719
+ if (!transactionId) {
720
+ transactionId = this._nextUniqueID()
721
+ }
722
+ const nativeCharacteristic = await this._callPromise(
723
+ BleModule.readCharacteristicForDevice(deviceIdentifier, serviceUUID, characteristicUUID, transactionId)
724
+ )
725
+ return new Characteristic(nativeCharacteristic, this)
726
+ }
727
+
728
+ /**
729
+ * Read {@link Characteristic} value.
730
+ *
731
+ * @param {Identifier} serviceIdentifier {@link Service} ID.
732
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
733
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
734
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
735
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified
736
+ * UUID paths. Latest value of {@link Characteristic} will be stored inside returned object.
737
+ * @private
738
+ */
739
+ async _readCharacteristicForService(
740
+ serviceIdentifier: Identifier,
741
+ characteristicUUID: UUID,
742
+ transactionId: ?TransactionId
743
+ ): Promise<Characteristic> {
744
+ if (!transactionId) {
745
+ transactionId = this._nextUniqueID()
746
+ }
747
+ const nativeCharacteristic = await this._callPromise(
748
+ BleModule.readCharacteristicForService(serviceIdentifier, characteristicUUID, transactionId)
749
+ )
750
+ return new Characteristic(nativeCharacteristic, this)
751
+ }
752
+
753
+ /**
754
+ * Read {@link Characteristic} value.
755
+ *
756
+ * @param {Identifier} characteristicIdentifier {@link Characteristic} ID.
757
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
758
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
759
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified ID.
760
+ * Latest value of {@link Characteristic} will be stored inside returned object.
761
+ * @private
762
+ */
763
+ async _readCharacteristic(
764
+ characteristicIdentifier: Identifier,
765
+ transactionId: ?TransactionId
766
+ ): Promise<Characteristic> {
767
+ if (!transactionId) {
768
+ transactionId = this._nextUniqueID()
769
+ }
770
+ const nativeCharacteristic = await this._callPromise(
771
+ BleModule.readCharacteristic(characteristicIdentifier, transactionId)
772
+ )
773
+ return new Characteristic(nativeCharacteristic, this)
774
+ }
775
+
776
+ /**
777
+ * Write {@link Characteristic} value with response.
778
+ *
779
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
780
+ * @param {UUID} serviceUUID {@link Service} UUID.
781
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
782
+ * @param {Base64} base64Value Value in Base64 format.
783
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
784
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
785
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified
786
+ * UUID paths. Latest value of characteristic may not be stored inside returned object.
787
+ */
788
+ async writeCharacteristicWithResponseForDevice(
789
+ deviceIdentifier: DeviceId,
790
+ serviceUUID: UUID,
791
+ characteristicUUID: UUID,
792
+ base64Value: Base64,
793
+ transactionId: ?TransactionId
794
+ ): Promise<Characteristic> {
795
+ if (!transactionId) {
796
+ transactionId = this._nextUniqueID()
797
+ }
798
+ const nativeCharacteristic = await this._callPromise(
799
+ BleModule.writeCharacteristicForDevice(
800
+ deviceIdentifier,
801
+ serviceUUID,
802
+ characteristicUUID,
803
+ base64Value,
804
+ true,
805
+ transactionId
806
+ )
807
+ )
808
+ return new Characteristic(nativeCharacteristic, this)
809
+ }
810
+
811
+ /**
812
+ * Write {@link Characteristic} value with response.
813
+ *
814
+ * @param {Identifier} serviceIdentifier {@link Service} ID.
815
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
816
+ * @param {Base64} base64Value Value in Base64 format.
817
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
818
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
819
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified
820
+ * UUID paths. Latest value of characteristic may not be stored inside returned object.
821
+ * @private
822
+ */
823
+ async _writeCharacteristicWithResponseForService(
824
+ serviceIdentifier: Identifier,
825
+ characteristicUUID: UUID,
826
+ base64Value: Base64,
827
+ transactionId: ?TransactionId
828
+ ): Promise<Characteristic> {
829
+ if (!transactionId) {
830
+ transactionId = this._nextUniqueID()
831
+ }
832
+ const nativeCharacteristic = await this._callPromise(
833
+ BleModule.writeCharacteristicForService(serviceIdentifier, characteristicUUID, base64Value, true, transactionId)
834
+ )
835
+ return new Characteristic(nativeCharacteristic, this)
836
+ }
837
+
838
+ /**
839
+ * Write {@link Characteristic} value with response.
840
+ *
841
+ * @param {Identifier} characteristicIdentifier {@link Characteristic} ID.
842
+ * @param {Base64} base64Value Value in Base64 format.
843
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
844
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
845
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified ID.
846
+ * Latest value of characteristic may not be stored inside returned object.
847
+ * @private
848
+ */
849
+ async _writeCharacteristicWithResponse(
850
+ characteristicIdentifier: Identifier,
851
+ base64Value: Base64,
852
+ transactionId: ?TransactionId
853
+ ): Promise<Characteristic> {
854
+ if (!transactionId) {
855
+ transactionId = this._nextUniqueID()
856
+ }
857
+ const nativeCharacteristic = await this._callPromise(
858
+ BleModule.writeCharacteristic(characteristicIdentifier, base64Value, true, transactionId)
859
+ )
860
+ return new Characteristic(nativeCharacteristic, this)
861
+ }
862
+
863
+ /**
864
+ * Write {@link Characteristic} value without response.
865
+ *
866
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
867
+ * @param {UUID} serviceUUID {@link Service} UUID.
868
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
869
+ * @param {Base64} base64Value Value in Base64 format.
870
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
871
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
872
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified
873
+ * UUID paths. Latest value of characteristic may not be stored inside returned object.
874
+ */
875
+ async writeCharacteristicWithoutResponseForDevice(
876
+ deviceIdentifier: DeviceId,
877
+ serviceUUID: UUID,
878
+ characteristicUUID: UUID,
879
+ base64Value: Base64,
880
+ transactionId: ?TransactionId
881
+ ): Promise<Characteristic> {
882
+ if (!transactionId) {
883
+ transactionId = this._nextUniqueID()
884
+ }
885
+ const nativeCharacteristic = await this._callPromise(
886
+ BleModule.writeCharacteristicForDevice(
887
+ deviceIdentifier,
888
+ serviceUUID,
889
+ characteristicUUID,
890
+ base64Value,
891
+ false,
892
+ transactionId
893
+ )
894
+ )
895
+ return new Characteristic(nativeCharacteristic, this)
896
+ }
897
+
898
+ /**
899
+ * Write {@link Characteristic} value without response.
900
+ *
901
+ * @param {Identifier} serviceIdentifier {@link Service} ID.
902
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
903
+ * @param {Base64} base64Value Value in Base64 format.
904
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
905
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
906
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified
907
+ * UUID paths. Latest value of characteristic may not be stored inside returned object.
908
+ * @private
909
+ */
910
+ async _writeCharacteristicWithoutResponseForService(
911
+ serviceIdentifier: Identifier,
912
+ characteristicUUID: UUID,
913
+ base64Value: Base64,
914
+ transactionId: ?TransactionId
915
+ ): Promise<Characteristic> {
916
+ if (!transactionId) {
917
+ transactionId = this._nextUniqueID()
918
+ }
919
+ const nativeCharacteristic = await this._callPromise(
920
+ BleModule.writeCharacteristicForService(serviceIdentifier, characteristicUUID, base64Value, false, transactionId)
921
+ )
922
+ return new Characteristic(nativeCharacteristic, this)
923
+ }
924
+
925
+ /**
926
+ * Write {@link Characteristic} value without response.
927
+ *
928
+ * @param {Identifier} characteristicIdentifier {@link Characteristic} UUID.
929
+ * @param {Base64} base64Value Value in Base64 format.
930
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
931
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
932
+ * @returns {Promise<Characteristic>} Promise which emits first {@link Characteristic} object matching specified ID.
933
+ * Latest value of characteristic may not be stored inside returned object.
934
+ * @private
935
+ */
936
+ async _writeCharacteristicWithoutResponse(
937
+ characteristicIdentifier: Identifier,
938
+ base64Value: Base64,
939
+ transactionId: ?TransactionId
940
+ ): Promise<Characteristic> {
941
+ if (!transactionId) {
942
+ transactionId = this._nextUniqueID()
943
+ }
944
+ const nativeCharacteristic = await this._callPromise(
945
+ BleModule.writeCharacteristic(characteristicIdentifier, base64Value, false, transactionId)
946
+ )
947
+ return new Characteristic(nativeCharacteristic, this)
948
+ }
949
+
950
+ /**
951
+ * Monitor value changes of a {@link Characteristic}. If notifications are enabled they will be used
952
+ * in favour of indications.
953
+ *
954
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
955
+ * @param {UUID} serviceUUID {@link Service} UUID.
956
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
957
+ * @param {function(error: ?BleError, characteristic: ?Characteristic)} listener - callback which emits
958
+ * {@link Characteristic} objects with modified value for each notification.
959
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
960
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
961
+ * @returns {Subscription} Subscription on which `remove()` function can be called to unsubscribe.
962
+ */
963
+ monitorCharacteristicForDevice(
964
+ deviceIdentifier: DeviceId,
965
+ serviceUUID: UUID,
966
+ characteristicUUID: UUID,
967
+ listener: (error: ?BleError, characteristic: ?Characteristic) => void,
968
+ transactionId: ?TransactionId,
969
+ subscriptionType: ?CharacteristicSubscriptionType
970
+ ): Subscription {
971
+ const filledTransactionId = transactionId || this._nextUniqueID()
972
+ const commonArgs = [deviceIdentifier, serviceUUID, characteristicUUID, filledTransactionId]
973
+ const args = isIOS ? commonArgs : [...commonArgs, subscriptionType]
974
+
975
+ return this._handleMonitorCharacteristic(
976
+ BleModule.monitorCharacteristicForDevice(...args),
977
+ filledTransactionId,
978
+ listener
979
+ )
980
+ }
981
+
982
+ /**
983
+ * Monitor value changes of a {@link Characteristic}. If notifications are enabled they will be used
984
+ * in favour of indications.
985
+ *
986
+ * @param {Identifier} serviceIdentifier {@link Service} ID.
987
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
988
+ * @param {function(error: ?BleError, characteristic: ?Characteristic)} listener - callback which emits
989
+ * {@link Characteristic} objects with modified value for each notification.
990
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
991
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
992
+ * @returns {Subscription} Subscription on which `remove()` function can be called to unsubscribe.
993
+ * @private
994
+ */
995
+ _monitorCharacteristicForService(
996
+ serviceIdentifier: Identifier,
997
+ characteristicUUID: UUID,
998
+ listener: (error: ?BleError, characteristic: ?Characteristic) => void,
999
+ transactionId: ?TransactionId,
1000
+ subscriptionType: ?CharacteristicSubscriptionType
1001
+ ): Subscription {
1002
+ const filledTransactionId = transactionId || this._nextUniqueID()
1003
+ const commonArgs = [serviceIdentifier, characteristicUUID, filledTransactionId]
1004
+ const args = isIOS ? commonArgs : [...commonArgs, subscriptionType]
1005
+
1006
+ return this._handleMonitorCharacteristic(
1007
+ BleModule.monitorCharacteristicForService(...args),
1008
+ filledTransactionId,
1009
+ listener
1010
+ )
1011
+ }
1012
+
1013
+ /**
1014
+ * Monitor value changes of a {@link Characteristic}. If notifications are enabled they will be used
1015
+ * in favour of indications.
1016
+ *
1017
+ * @param {Identifier} characteristicIdentifier - {@link Characteristic} ID.
1018
+ * @param {function(error: ?BleError, characteristic: ?Characteristic)} listener - callback which emits
1019
+ * {@link Characteristic} objects with modified value for each notification.
1020
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
1021
+ * @param {?CharacteristicSubscriptionType} subscriptionType subscription type of the characteristic
1022
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
1023
+ * @returns {Subscription} Subscription on which `remove()` function can be called to unsubscribe.
1024
+ * @private
1025
+ */
1026
+ _monitorCharacteristic(
1027
+ characteristicIdentifier: Identifier,
1028
+ listener: (error: ?BleError, characteristic: ?Characteristic) => void,
1029
+ transactionId: ?TransactionId,
1030
+ subscriptionType: ?CharacteristicSubscriptionType
1031
+ ): Subscription {
1032
+ const filledTransactionId = transactionId || this._nextUniqueID()
1033
+ const commonArgs = [characteristicIdentifier, filledTransactionId]
1034
+ const args = isIOS ? commonArgs : [...commonArgs, subscriptionType]
1035
+
1036
+ return this._handleMonitorCharacteristic(
1037
+ BleModule.monitorCharacteristic(...args),
1038
+ filledTransactionId,
1039
+ listener
1040
+ )
1041
+ }
1042
+
1043
+ /**
1044
+ * Common code to handle characteristic monitoring.
1045
+ *
1046
+ * @param {Promise<void>} monitorPromise Characteristic monitoring promise
1047
+ * @param {TransactionId} transactionId TransactionId of passed promise
1048
+ * @param {function(error: ?BleError, characteristic: ?Characteristic)} listener - callback which emits
1049
+ * {@link Characteristic} objects with modified value for each notification.
1050
+ * @returns {Subscription} Subscription on which `remove()` function can be called to unsubscribe.
1051
+ * @private
1052
+ */
1053
+ _handleMonitorCharacteristic(
1054
+ monitorPromise: Promise<void>,
1055
+ transactionId: TransactionId,
1056
+ listener: (error: ?BleError, characteristic: ?Characteristic) => void
1057
+ ): Subscription {
1058
+ const monitorListener = ([error, characteristic, msgTransactionId]: [
1059
+ ?string,
1060
+ NativeCharacteristic,
1061
+ TransactionId
1062
+ ]) => {
1063
+ if (transactionId !== msgTransactionId) {
1064
+ return
1065
+ }
1066
+ if (error) {
1067
+ listener(parseBleError(error, this._errorCodesToMessagesMapping), null)
1068
+ return
1069
+ }
1070
+ listener(null, new Characteristic(characteristic, this))
1071
+ }
1072
+
1073
+ const subscription: Subscription = this._eventEmitter.addListener(Platform.OS === 'harmony' ? 'ReadEvent' : BleModule.ReadEvent, monitorListener)
1074
+
1075
+ const id = this._nextUniqueID()
1076
+ const wrappedSubscription: Subscription = {
1077
+ remove: () => {
1078
+ if (this._activeSubscriptions[id] != null) {
1079
+ delete this._activeSubscriptions[id]
1080
+ subscription.remove()
1081
+ }
1082
+ }
1083
+ }
1084
+ this._activeSubscriptions[id] = wrappedSubscription
1085
+
1086
+ this._callPromise(monitorPromise).then(
1087
+ () => {
1088
+ wrappedSubscription.remove()
1089
+ },
1090
+ (error: BleError) => {
1091
+ listener(error, null)
1092
+ wrappedSubscription.remove()
1093
+ }
1094
+ )
1095
+
1096
+ return {
1097
+ remove: () => {
1098
+ BleModule.cancelTransaction(transactionId)
1099
+ }
1100
+ }
1101
+ }
1102
+
1103
+ // Mark: Descriptors operations ----------------------------------------------------------------------------------
1104
+
1105
+ /**
1106
+ * Read {@link Descriptor} value.
1107
+ *
1108
+ * @param {DeviceId} deviceIdentifier {@link Device} identifier.
1109
+ * @param {UUID} serviceUUID {@link Service} UUID.
1110
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
1111
+ * @param {UUID} descriptorUUID {@link Descriptor} UUID.
1112
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
1113
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
1114
+ * @returns {Promise<Descriptor>} Promise which emits first {@link Descriptor} object matching specified
1115
+ * UUID paths. Latest value of {@link Descriptor} will be stored inside returned object.
1116
+ */
1117
+ async readDescriptorForDevice(
1118
+ deviceIdentifier: DeviceId,
1119
+ serviceUUID: UUID,
1120
+ characteristicUUID: UUID,
1121
+ descriptorUUID: UUID,
1122
+ transactionId: ?TransactionId
1123
+ ): Promise<Descriptor> {
1124
+ if (!transactionId) {
1125
+ transactionId = this._nextUniqueID()
1126
+ }
1127
+ const nativeDescriptor = await this._callPromise(
1128
+ BleModule.readDescriptorForDevice(
1129
+ deviceIdentifier,
1130
+ serviceUUID,
1131
+ characteristicUUID,
1132
+ descriptorUUID,
1133
+ transactionId
1134
+ )
1135
+ )
1136
+ return new Descriptor(nativeDescriptor, this)
1137
+ }
1138
+
1139
+ /**
1140
+ * Read {@link Descriptor} value.
1141
+ *
1142
+ * @param {Identifier} serviceIdentifier {@link Service} identifier.
1143
+ * @param {UUID} characteristicUUID {@link Characteristic} UUID.
1144
+ * @param {UUID} descriptorUUID {@link Descriptor} UUID.
1145
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
1146
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
1147
+ * @returns {Promise<Descriptor>} Promise which emits first {@link Descriptor} object matching specified
1148
+ * UUID paths. Latest value of {@link Descriptor} will be stored inside returned object.
1149
+ * @private
1150
+ */
1151
+ async _readDescriptorForService(
1152
+ serviceIdentifier: Identifier,
1153
+ characteristicUUID: UUID,
1154
+ descriptorUUID: UUID,
1155
+ transactionId: ?TransactionId
1156
+ ): Promise<Descriptor> {
1157
+ if (!transactionId) {
1158
+ transactionId = this._nextUniqueID()
1159
+ }
1160
+ const nativeDescriptor = await this._callPromise(
1161
+ BleModule.readDescriptorForService(serviceIdentifier, characteristicUUID, descriptorUUID, transactionId)
1162
+ )
1163
+ return new Descriptor(nativeDescriptor, this)
1164
+ }
1165
+
1166
+ /**
1167
+ * Read {@link Descriptor} value.
1168
+ *
1169
+ * @param {Identifier} characteristicIdentifier {@link Characteristic} identifier.
1170
+ * @param {UUID} descriptorUUID {@link Descriptor} UUID.
1171
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
1172
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
1173
+ * @returns {Promise<Descriptor>} Promise which emits first {@link Descriptor} object matching specified
1174
+ * UUID paths. Latest value of {@link Descriptor} will be stored inside returned object.
1175
+ * @private
1176
+ */
1177
+ async _readDescriptorForCharacteristic(
1178
+ characteristicIdentifier: Identifier,
1179
+ descriptorUUID: UUID,
1180
+ transactionId: ?TransactionId
1181
+ ): Promise<Descriptor> {
1182
+ if (!transactionId) {
1183
+ transactionId = this._nextUniqueID()
1184
+ }
1185
+ const nativeDescriptor = await this._callPromise(
1186
+ BleModule.readDescriptorForCharacteristic(characteristicIdentifier, descriptorUUID, transactionId)
1187
+ )
1188
+ return new Descriptor(nativeDescriptor, this)
1189
+ }
1190
+
1191
+ /**
1192
+ * Read {@link Descriptor} value.
1193
+ *
1194
+ * @param {Identifier} descriptorIdentifier {@link Descriptor} identifier.
1195
+ * @param {?TransactionId} transactionId optional `transactionId` which can be used in
1196
+ * {@link #blemanagercanceltransaction|cancelTransaction()} function.
1197
+ * @returns {Promise<Descriptor>} Promise which emits first {@link Descriptor} object matching specified
1198
+ * UUID paths. Latest value of {@link Descriptor} will be stored inside returned object.
1199
+ * @private
1200
+ */
1201
+ async _readDescriptor(descriptorIdentifier: Identifier, transactionId: ?TransactionId): Promise<Descriptor> {
1202
+ if (!transactionId) {
1203
+ transactionId = this._nextUniqueID()
1204
+ }
1205
+ const nativeDescriptor = await this._callPromise(BleModule.readDescriptor(descriptorIdentifier, transactionId))
1206
+ return new Descriptor(nativeDescriptor, this)
1207
+ }
1208
+
1209
+ /**
1210
+ * Write {@link Descriptor} value.
1211
+ *
1212
+ * @param {DeviceId} deviceIdentifier Connected device identifier
1213
+ * @param {UUID} serviceUUID Service UUID
1214
+ * @param {UUID} characteristicUUID Characteristic UUID
1215
+ * @param {UUID} descriptorUUID Descriptor UUID
1216
+ * @param {Base64} valueBase64 Value to be set coded in Base64
1217
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
1218
+ * @returns {Promise<Descriptor>} Descriptor which saved passed value
1219
+ */
1220
+ async writeDescriptorForDevice(
1221
+ deviceIdentifier: DeviceId,
1222
+ serviceUUID: UUID,
1223
+ characteristicUUID: UUID,
1224
+ descriptorUUID: UUID,
1225
+ valueBase64: Base64,
1226
+ transactionId: ?TransactionId
1227
+ ): Promise<Descriptor> {
1228
+ if (!transactionId) {
1229
+ transactionId = this._nextUniqueID()
1230
+ }
1231
+ const nativeDescriptor = await this._callPromise(
1232
+ BleModule.writeDescriptorForDevice(
1233
+ deviceIdentifier,
1234
+ serviceUUID,
1235
+ characteristicUUID,
1236
+ descriptorUUID,
1237
+ valueBase64,
1238
+ transactionId
1239
+ )
1240
+ )
1241
+ return new Descriptor(nativeDescriptor, this)
1242
+ }
1243
+
1244
+ /**
1245
+ * Write {@link Descriptor} value.
1246
+ *
1247
+ * @param {Identifier} serviceIdentifier Service identifier
1248
+ * @param {UUID} characteristicUUID Characteristic UUID
1249
+ * @param {UUID} descriptorUUID Descriptor UUID
1250
+ * @param {Base64} valueBase64 Value to be set coded in Base64
1251
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
1252
+ * @returns {Promise<Descriptor>} Descriptor which saved passed value
1253
+ * @private
1254
+ */
1255
+ async _writeDescriptorForService(
1256
+ serviceIdentifier: Identifier,
1257
+ characteristicUUID: UUID,
1258
+ descriptorUUID: UUID,
1259
+ valueBase64: Base64,
1260
+ transactionId: ?TransactionId
1261
+ ): Promise<Descriptor> {
1262
+ if (!transactionId) {
1263
+ transactionId = this._nextUniqueID()
1264
+ }
1265
+ const nativeDescriptor = await this._callPromise(
1266
+ BleModule.writeDescriptorForService(
1267
+ serviceIdentifier,
1268
+ characteristicUUID,
1269
+ descriptorUUID,
1270
+ valueBase64,
1271
+ transactionId
1272
+ )
1273
+ )
1274
+ return new Descriptor(nativeDescriptor, this)
1275
+ }
1276
+
1277
+ /**
1278
+ * Write {@link Descriptor} value.
1279
+ *
1280
+ * @param {Identifier} characteristicIdentifier Characteristic identifier
1281
+ * @param {UUID} descriptorUUID Descriptor UUID
1282
+ * @param {Base64} valueBase64 Value to be set coded in Base64
1283
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
1284
+ * @returns {Promise<Descriptor>} Descriptor which saved passed value
1285
+ * @private
1286
+ */
1287
+ async _writeDescriptorForCharacteristic(
1288
+ characteristicIdentifier: Identifier,
1289
+ descriptorUUID: UUID,
1290
+ valueBase64: Base64,
1291
+ transactionId: ?TransactionId
1292
+ ): Promise<Descriptor> {
1293
+ if (!transactionId) {
1294
+ transactionId = this._nextUniqueID()
1295
+ }
1296
+ const nativeDescriptor = await this._callPromise(
1297
+ BleModule.writeDescriptorForCharacteristic(characteristicIdentifier, descriptorUUID, valueBase64, transactionId)
1298
+ )
1299
+ return new Descriptor(nativeDescriptor, this)
1300
+ }
1301
+
1302
+ /**
1303
+ * Write {@link Descriptor} value.
1304
+ *
1305
+ * @param {Identifier} descriptorIdentifier Descriptor identifier
1306
+ * @param {Base64} valueBase64 Value to be set coded in Base64
1307
+ * @param {?TransactionId} transactionId Transaction handle used to cancel operation
1308
+ * @returns {Promise<Descriptor>} Descriptor which saved passed value
1309
+ * @private
1310
+ */
1311
+ async _writeDescriptor(
1312
+ descriptorIdentifier: Identifier,
1313
+ valueBase64: Base64,
1314
+ transactionId: ?TransactionId
1315
+ ): Promise<Descriptor> {
1316
+ if (!transactionId) {
1317
+ transactionId = this._nextUniqueID()
1318
+ }
1319
+ const nativeDescriptor = await this._callPromise(
1320
+ BleModule.writeDescriptor(descriptorIdentifier, valueBase64, transactionId)
1321
+ )
1322
+ return new Descriptor(nativeDescriptor, this)
1323
+ }
1324
+ }