@wemap/providers 3.0.0

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 (102) hide show
  1. package/babel.config.js +11 -0
  2. package/config.json +4 -0
  3. package/debug/absolute-attitude.html +16 -0
  4. package/debug/absolute-position.html +16 -0
  5. package/debug/attitude.html +16 -0
  6. package/debug/components/AbsoluteAttitudeComponent.jsx +142 -0
  7. package/debug/components/AbsolutePositionComponent.jsx +79 -0
  8. package/debug/components/AttitudeComponent.jsx +40 -0
  9. package/debug/components/Common.css +27 -0
  10. package/debug/components/GnssWifiComponent.jsx +53 -0
  11. package/debug/components/ImuComponent.jsx +53 -0
  12. package/debug/components/InclinationComponent.jsx +68 -0
  13. package/debug/components/MapComponent.jsx +366 -0
  14. package/debug/components/NavigationConfig.js +112 -0
  15. package/debug/components/PoseComponent.jsx +168 -0
  16. package/debug/components/RelativeAttitudeComponent.jsx +85 -0
  17. package/debug/components/StartStopComponent.jsx +45 -0
  18. package/debug/components/StepDetectionComponent.jsx +39 -0
  19. package/debug/components/Utils.js +216 -0
  20. package/debug/components/index.js +30 -0
  21. package/debug/components/old/PositioningComponent.jsx +29 -0
  22. package/debug/components/old/PositioningInclinationComponent.jsx +82 -0
  23. package/debug/components/old/PositioningPoseComponent.jsx +117 -0
  24. package/debug/gnss-wifi.html +16 -0
  25. package/debug/imu.html +16 -0
  26. package/debug/inclination.html +16 -0
  27. package/debug/pose.html +16 -0
  28. package/debug/positioning-legacy.html +16 -0
  29. package/debug/relative-attitude.html +16 -0
  30. package/debug/step-detection.html +16 -0
  31. package/index.js +7 -0
  32. package/package.json +67 -0
  33. package/src/Providers.js +80 -0
  34. package/src/ProvidersInterface.js +125 -0
  35. package/src/ProvidersOptions.js +29 -0
  36. package/src/errors/AskImuOnDesktopError.js +9 -0
  37. package/src/errors/ContainsIgnoredProviderError.js +9 -0
  38. package/src/errors/GeolocationApiMissingError.js +9 -0
  39. package/src/errors/GeolocationPermissionDeniedError.js +9 -0
  40. package/src/errors/GeolocationPositionUnavailableError.js +9 -0
  41. package/src/errors/IpResolveServerError.js +9 -0
  42. package/src/errors/MissingAccelerometerError.js +11 -0
  43. package/src/errors/MissingArCoreError.js +9 -0
  44. package/src/errors/MissingGyroscopeError.js +11 -0
  45. package/src/errors/MissingMagnetometerError.js +9 -0
  46. package/src/errors/MissingNativeInterfaceError.js +9 -0
  47. package/src/errors/MissingSensorError.js +14 -0
  48. package/src/errors/NoProviderFoundError.js +9 -0
  49. package/src/events/Availability.js +44 -0
  50. package/src/events/EventType.js +33 -0
  51. package/src/events/ProviderEvent.js +32 -0
  52. package/src/events/ProvidersLogger.js +83 -0
  53. package/src/providers/Constants.js +5 -0
  54. package/src/providers/FakeProvider.spec.js +57 -0
  55. package/src/providers/MetaProvider.js +42 -0
  56. package/src/providers/Provider.js +314 -0
  57. package/src/providers/Provider.spec.js +136 -0
  58. package/src/providers/ProviderState.js +5 -0
  59. package/src/providers/attitude/AttitudeProvider.js +63 -0
  60. package/src/providers/attitude/EkfAttitude.js +224 -0
  61. package/src/providers/attitude/EkfAttitude.spec.js +114 -0
  62. package/src/providers/attitude/absolute/AbsoluteAttitudeFromBrowserProvider.js +224 -0
  63. package/src/providers/attitude/absolute/AbsoluteAttitudeFromRelAttProvider.js +134 -0
  64. package/src/providers/attitude/absolute/AbsoluteAttitudeProvider.js +143 -0
  65. package/src/providers/attitude/relative/RelativeAttitudeFromBrowserProvider.js +89 -0
  66. package/src/providers/attitude/relative/RelativeAttitudeFromEkfProvider.js +114 -0
  67. package/src/providers/attitude/relative/RelativeAttitudeProvider.js +103 -0
  68. package/src/providers/imu/AccelerometerProvider.js +61 -0
  69. package/src/providers/imu/GyroscopeProvider.js +61 -0
  70. package/src/providers/imu/ImuProvider.js +122 -0
  71. package/src/providers/inclination/InclinationFromAccProvider.js +87 -0
  72. package/src/providers/inclination/InclinationFromAttitudeProvider.js +77 -0
  73. package/src/providers/inclination/InclinationProvider.js +69 -0
  74. package/src/providers/legacy/AbsolutePdrProvider.js +258 -0
  75. package/src/providers/legacy/ArCoreAbsoluteProvider.js +230 -0
  76. package/src/providers/legacy/GnssWifiPdrProvider.js +217 -0
  77. package/src/providers/legacy/MapMatchingProvider.js +65 -0
  78. package/src/providers/legacy/PdrProvider.old.js +300 -0
  79. package/src/providers/legacy/PoseProvider.js +68 -0
  80. package/src/providers/legacy/helpers/HeadingUnlocker.js +47 -0
  81. package/src/providers/legacy/helpers/HeadingUnlocker.spec.js +53 -0
  82. package/src/providers/legacy/helpers/Smoother.js +92 -0
  83. package/src/providers/legacy/helpers/Smoother.spec.js +426 -0
  84. package/src/providers/legacy/helpers/ThugDetector.js +37 -0
  85. package/src/providers/others/CameraNativeProvider.js +44 -0
  86. package/src/providers/position/absolute/AbsolutePositionFromRelProvider.js +109 -0
  87. package/src/providers/position/absolute/AbsolutePositionProvider.js +172 -0
  88. package/src/providers/position/absolute/GnssWifiProvider.js +122 -0
  89. package/src/providers/position/absolute/IpProvider.js +68 -0
  90. package/src/providers/position/relative/ArCoreProvider.js +197 -0
  91. package/src/providers/position/relative/GeoRelativePositionFromArCoreProvider.js +85 -0
  92. package/src/providers/position/relative/GeoRelativePositionProvider.js +66 -0
  93. package/src/providers/position/relative/PdrProvider.js +132 -0
  94. package/src/providers/steps/StepDetectionLadetto.js +67 -0
  95. package/src/providers/steps/StepDetectionMinMaxPeaks.js +80 -0
  96. package/src/providers/steps/StepDetectionMinMaxPeaks2.js +108 -0
  97. package/src/providers/steps/StepDetectionProvider.js +100 -0
  98. package/src/smoothers/PositionSmoother.js +86 -0
  99. package/src/smoothers/PositionSmoother.spec.js +55 -0
  100. package/webpack/webpack.common.js +20 -0
  101. package/webpack/webpack.dev.js +24 -0
  102. package/webpack/webpack.prod.js +15 -0
@@ -0,0 +1,83 @@
1
+ import Logger from '@wemap/logger';
2
+
3
+ let currentId = 0;
4
+ const objectsIdMap = new WeakMap();
5
+
6
+ let pushEvents = {};
7
+ let pushEventsRef = {};
8
+
9
+ let interval;
10
+ let initDate;
11
+
12
+ class ProvidersLogger {
13
+
14
+ static _enabled = false;
15
+
16
+ static get enabled() {
17
+ return this._enabled;
18
+ }
19
+
20
+ static set enabled(_newVal) {
21
+ this._enabled = _newVal;
22
+ }
23
+
24
+ static initializeInterval() {
25
+
26
+ if (interval) {
27
+ return;
28
+ }
29
+
30
+ interval = setInterval(() => {
31
+
32
+ for (const [key, value] of Object.entries(pushEvents)) {
33
+ Logger.debug('Received ' + value + ' notifications from ' + pushEventsRef[key].constructor.name + ' last second');
34
+ }
35
+
36
+ pushEvents = {};
37
+ pushEventsRef = {};
38
+ }, 1000);
39
+ }
40
+
41
+ static getObjectId(object) {
42
+ if (!objectsIdMap.has(object)) {
43
+ objectsIdMap.set(object, ++currentId);
44
+ }
45
+ return objectsIdMap.get(object);
46
+ }
47
+
48
+ static addEvent(object, method) {
49
+
50
+ if (!ProvidersLogger.enabled) {
51
+ return;
52
+ }
53
+
54
+ if (!initDate) {
55
+ initDate = Date.now();
56
+ }
57
+
58
+ ProvidersLogger.initializeInterval();
59
+
60
+ const objectId = ProvidersLogger.getObjectId(object);
61
+ const objectClassName = object.constructor.name;
62
+
63
+ Logger.debug(objectClassName + '[' + objectId + '].' + method);
64
+ }
65
+
66
+ static incrementNotifications(object) {
67
+
68
+ if (!ProvidersLogger.enabled) {
69
+ return;
70
+ }
71
+
72
+ const objectId = ProvidersLogger.getObjectId(object);
73
+
74
+ let counter = pushEvents[objectId];
75
+ if (!counter) {
76
+ counter = 0;
77
+ pushEventsRef[objectId] = object;
78
+ }
79
+ pushEvents[objectId] = counter + 1;
80
+ }
81
+
82
+ }
83
+ export default ProvidersLogger;
@@ -0,0 +1,5 @@
1
+ const Constants = {
2
+ DEFAULT_ALTITUDE: 1.6
3
+ };
4
+
5
+ export default Constants;
@@ -0,0 +1,57 @@
1
+ import { UserPosition } from '@wemap/geo';
2
+
3
+ import Provider from './Provider';
4
+ import Availability from '../events/Availability';
5
+
6
+ import EventType from '../events/EventType';
7
+ import { TimeUtils } from '@wemap/utils';
8
+
9
+ class FakeProvider1 extends Provider { }
10
+
11
+ class FakeProvider5 extends Provider {
12
+ start() {}
13
+ }
14
+
15
+ class FakeProvider2 extends Provider {
16
+ get _availability() {
17
+ return Availability.no(new Error());
18
+ }
19
+ start() { }
20
+ stop() { }
21
+ }
22
+
23
+ class FakeProvider3 extends Provider {
24
+ start() {
25
+ this.intervalId = setInterval(() => {
26
+ const fakePosition = new UserPosition(Math.random() * 45, Math.random() * 180);
27
+ this.notify(this.createEvent(EventType.AbsolutePosition, fakePosition));
28
+ this.notify(this.createEvent(EventType.AbsolutePosition, fakePosition, TimeUtils.preciseTime));
29
+ }, 1);
30
+ }
31
+ stop() {
32
+ clearInterval(this.intervalId);
33
+ }
34
+ }
35
+
36
+ class FakeProvider4 extends Provider {
37
+ constructor() {
38
+ super();
39
+ this.fp3 = FakeProvider3.instance;
40
+ }
41
+ get _availability() {
42
+ return this.fp3.availability;
43
+ }
44
+ start() {
45
+ this.fp3id = this.fp3.addEventListener(
46
+ events => this.notify(events[0].clone()),
47
+ this.notifyError.bind(this),
48
+ this.name);
49
+ }
50
+ stop() {
51
+ this.fp3.removeEventListener(this.fp3id);
52
+ }
53
+ }
54
+
55
+ export {
56
+ FakeProvider1, FakeProvider2, FakeProvider3, FakeProvider4, FakeProvider5
57
+ };
@@ -0,0 +1,42 @@
1
+ import Provider from './Provider';
2
+ import ProviderEvent from '../events/ProviderEvent';
3
+
4
+ class MetaProvider extends Provider {
5
+
6
+ _lastEvent = null;
7
+
8
+ /**
9
+ * Singleton pattern using reflection.
10
+ * @returns {MetaProvider}
11
+ */
12
+ static get instance() {
13
+ if (!this._instance) {
14
+ this._instance = Reflect.construct(this, []);
15
+ }
16
+ return this._instance;
17
+ }
18
+
19
+ /**
20
+ * @override
21
+ * @param {ProviderEvent} event
22
+ */
23
+ notify(event) {
24
+ super.notify(event);
25
+ this._lastEvent = event;
26
+ }
27
+
28
+ get lastEvent() {
29
+ return this._lastEvent;
30
+ }
31
+
32
+ /**
33
+ * Input data from external interface
34
+ * @param {ProviderEvent} event
35
+ */
36
+ // eslint-disable-next-line no-unused-vars
37
+ feed(event) {
38
+ throw new Error('Not implemented');
39
+ }
40
+ }
41
+
42
+ export default MetaProvider;
@@ -0,0 +1,314 @@
1
+ import isNumber from 'lodash.isnumber';
2
+ import noop from 'lodash.noop';
3
+
4
+ import { TimeUtils } from '@wemap/utils';
5
+
6
+ import EventType from '../events/EventType';
7
+ import ProviderEvent from '../events/ProviderEvent';
8
+ import ProvidersLogger from '../events/ProvidersLogger';
9
+ import Availability from '../events/Availability';
10
+ import ContainsIgnoredProviderError from '../errors/ContainsIgnoredProviderError';
11
+ import ProvidersOptions from '../ProvidersOptions';
12
+ import ProviderState from './ProviderState';
13
+
14
+ let uniqueId = 1;
15
+
16
+ /**
17
+ * A provider is a meta class to define an entity which can be
18
+ * started / stopped and provides a data of {@link ProviderEvent#DataType}
19
+ */
20
+ class Provider {
21
+
22
+ static _callbackUniqueId = 0;
23
+
24
+ state = ProviderState.STOPPPED;
25
+
26
+ _eventsCallbacks = [];
27
+ _monitoringCallbacks = [];
28
+
29
+
30
+ /**
31
+ * Singleton pattern using reflection.
32
+ * @returns {Provider}
33
+ */
34
+ static get instance() {
35
+ if (!this._instance) {
36
+ this._instance = Reflect.construct(this, []);
37
+ }
38
+ return this._instance;
39
+ }
40
+
41
+
42
+ /**
43
+ * Provider constructor
44
+ */
45
+ constructor() {
46
+
47
+ if (this.constructor === Provider) {
48
+ throw new Error('Can\'t instantiate Provider directly');
49
+ }
50
+
51
+ if (this._instance) {
52
+ throw new Error(`Cannot instantiate ${this.constructor.name} twice`);
53
+ }
54
+
55
+ this.id = uniqueId++;
56
+
57
+ ProvidersLogger.addEvent(this, 'constructor');
58
+ }
59
+
60
+ get name() {
61
+ return this.constructor.name;
62
+ }
63
+
64
+ /**
65
+ * Get the provider name
66
+ * @public
67
+ * @abstract
68
+ */
69
+ static get displayName() {
70
+ return this.name;
71
+ }
72
+
73
+ get displayName() {
74
+ return this.constructor.displayName;
75
+ }
76
+
77
+ /**
78
+ * Get the list of events type which can be returned by the provider
79
+ * @returns {EventType[]} the list of events type
80
+ * @public
81
+ * @abstract
82
+ */
83
+ get eventsType() {
84
+ return [];
85
+ }
86
+
87
+ /**
88
+ * @returns {Availability} returns an availability
89
+ */
90
+ get availability() {
91
+ if (ProvidersOptions.ignoreProviders.includes(this.name)) {
92
+ return Availability.no(new ContainsIgnoredProviderError());
93
+ }
94
+
95
+ return this._availability;
96
+ }
97
+
98
+ get _availability() {
99
+ return Availability.yes();
100
+ }
101
+
102
+ /**
103
+ * Create an event from current provider
104
+ * @param {ProviderEvent#DataType} dataType type of ProviderEvent
105
+ * @param {Object} data data exported to ProviderEvent
106
+ * @param {Number} timestamp event timestamp
107
+ * @returns {ProviderEvent}
108
+ * @protected
109
+ */
110
+ static createEvent(dataType, data, timestamp, fromEvents = []) {
111
+ const event = new ProviderEvent(dataType, data);
112
+ event.timestamp = isNumber(timestamp) ? timestamp : TimeUtils.preciseTime / 1e3;
113
+ const newStack = fromEvents.reduce((acc, _event) => acc.concat(_event.providersStack), []);
114
+ // Remove duplicates and keep lasts
115
+ event.providersStack = [...new Set(newStack.reverse())].reverse();
116
+ return event;
117
+ }
118
+
119
+ /**
120
+ * Create an event from current provider
121
+ * @param {EventType} dataType type of ProviderEvent
122
+ * @param {Object} data data exported to ProviderEvent
123
+ * @param {Number} timestamp event timestamp
124
+ * @param {ProviderEvent[]} fromEvents events used for the creation of the new one
125
+ * @returns {ProviderEvent}
126
+ * @protected
127
+ */
128
+ createEvent(dataType, data, timestamp, fromEvents) {
129
+ return this.constructor.createEvent(dataType, data, timestamp, fromEvents);
130
+ }
131
+
132
+ get hasNativeInterface() {
133
+ return Boolean(this.nativeInterface);
134
+ }
135
+
136
+ get nativeInterface() {
137
+ return global.WemapProvidersAndroid || null;
138
+ }
139
+
140
+ get useCameraNatively() {
141
+ return false;
142
+ }
143
+
144
+ /**
145
+ *
146
+ * @param {Function} onEvents
147
+ * @param {Function} onError
148
+ * @param {Object} callerName
149
+ * @param {Boolean} startIfNecessary
150
+ * @returns {Number}
151
+ */
152
+ addEventListener(onEvents = noop, onError = noop, callerName = null, startIfNecessary = true) {
153
+ const id = ++Provider._callbackUniqueId;
154
+
155
+ /**
156
+ * Build callback
157
+ */
158
+ this._eventsCallbacks.push({
159
+ id,
160
+ onEvents,
161
+ onError,
162
+ optional: !startIfNecessary,
163
+ callerName
164
+ });
165
+
166
+
167
+ // The caller just want to have callbacks without starting the provider,
168
+ // the routine can be stopped here
169
+ if (!startIfNecessary) {
170
+ return id;
171
+ }
172
+
173
+
174
+ // If the provider is already started do not go further
175
+ if (this.state !== ProviderState.STOPPPED) {
176
+ return id;
177
+ }
178
+
179
+ // Check availability on start if defined in options
180
+ if (ProvidersOptions.checkAvailabilityOnStart) {
181
+ if (!this.availability.isSupported) {
182
+ this.notifyError(this.availability.reason);
183
+ return id;
184
+ }
185
+ }
186
+
187
+ this.state = ProviderState.STARTING;
188
+
189
+ ProvidersLogger.addEvent(this, 'start');
190
+ // Call the child start function
191
+ this.start();
192
+
193
+ this.state = ProviderState.STARTED;
194
+
195
+ this._monitoringCallbacks.forEach(({ onStarted }) => onStarted());
196
+
197
+ return id;
198
+ }
199
+
200
+ /**
201
+ *
202
+ * @param {Number} callbackUniqueId
203
+ */
204
+ removeEventListener(callbackUniqueId) {
205
+
206
+ // Search the caller object in callbacks list
207
+ const callback = this._eventsCallbacks.find(_callback => _callback.id === callbackUniqueId);
208
+ if (!callback) {
209
+ // The callback object is not found. Maybe it is already stopped.
210
+ return;
211
+ }
212
+
213
+ // Remove the current callback from the list of the callbacks
214
+ this._eventsCallbacks = this._eventsCallbacks.filter(_callback => _callback !== callback);
215
+
216
+ // If this callback was optional, do not go further to stop the provider
217
+ if (callback.optional) {
218
+ return;
219
+ }
220
+
221
+ // If there is callbacks that are not optionals for start, do not stop the provider
222
+ if (this._eventsCallbacks.find(_callback => !_callback.optional)) {
223
+ return;
224
+ }
225
+
226
+ // If the provider is already stopped, do not stop it again.
227
+ // This condition can be true if checkAvailabilityOnStart is true and returns an error
228
+ if (this.state === ProviderState.STOPPPED) {
229
+ return;
230
+ }
231
+
232
+ ProvidersLogger.addEvent(this, 'stop');
233
+ // Call the child stop function
234
+ this.stop();
235
+
236
+ this.state = ProviderState.STOPPPED;
237
+
238
+ this._monitoringCallbacks.forEach(({ onStopped }) => onStopped());
239
+ }
240
+
241
+
242
+ /**
243
+ *
244
+ * @param {Function} onStarted
245
+ * @param {Function} onStopped
246
+ * @returns {Number}
247
+ */
248
+ addMonitoringListener(onStarted = noop, onStopped = noop) {
249
+ const id = ++this.constructor._callbackUniqueId;
250
+ this._monitoringCallbacks.push({
251
+ id,
252
+ onStarted,
253
+ onStopped
254
+ });
255
+ return id;
256
+ }
257
+
258
+ /**
259
+ *
260
+ * @param {Number} callbackUniqueId
261
+ */
262
+ removeMonitoringListener(callbackUniqueId) {
263
+ this._monitoringCallbacks = this._monitoringCallbacks.filter(
264
+ _callback => _callback.id !== callbackUniqueId
265
+ );
266
+ }
267
+
268
+ /**
269
+ * @abstract
270
+ */
271
+ start() {
272
+ throw new Error('Provider "' + this.name + '" does not @override start()');
273
+ }
274
+
275
+ /**
276
+ * @abstract
277
+ */
278
+ stop() {
279
+ throw new Error('Provider "' + this.name + '" does not @override stop()');
280
+ }
281
+
282
+
283
+ /**
284
+ * Notify the subscriber defined in {@link addEventListener}
285
+ * @param {ProviderEvent[]} events events to send to subscriber
286
+ */
287
+ notify(...events) {
288
+ // Logging
289
+ ProvidersLogger.incrementNotifications(this);
290
+
291
+ // Add current provider to the list of providers for this event.
292
+ events.forEach(event => event.providersStack.unshift(this.name));
293
+
294
+ // Notify callbacks
295
+ this._eventsCallbacks.forEach(({ onEvents }) => onEvents(events));
296
+ }
297
+
298
+ /**
299
+ * Notify the subscriber defined in {@link addEventListener}
300
+ * @param {Error} error The error raised
301
+ */
302
+ notifyError(error) {
303
+ this._eventsCallbacks.forEach(({
304
+ id, onError
305
+ }) => {
306
+ if (ProvidersOptions.stopOnError) {
307
+ this.removeEventListener(id);
308
+ }
309
+ onError(error);
310
+ });
311
+ }
312
+ }
313
+
314
+ export default Provider;
@@ -0,0 +1,136 @@
1
+ /* eslint-disable max-nested-callbacks */
2
+ import chai from 'chai';
3
+ import chaiAsPromised from 'chai-as-promised';
4
+ import noop from 'lodash.noop';
5
+
6
+ import Logger from '@wemap/logger';
7
+
8
+ import Provider from './Provider';
9
+
10
+ import ContainsIgnoredProviderError from '../errors/ContainsIgnoredProviderError';
11
+
12
+ import {
13
+ FakeProvider1, FakeProvider2, FakeProvider3, FakeProvider4, FakeProvider5
14
+ } from './FakeProvider.spec';
15
+ import ProvidersOptions from '../ProvidersOptions';
16
+ import ProviderState from './ProviderState';
17
+
18
+ chai.use(chaiAsPromised);
19
+ Logger.enable(false);
20
+
21
+ const { expect } = chai;
22
+
23
+
24
+ describe('Provider', () => {
25
+
26
+ it('creation/singleton', () => {
27
+ expect(() => new Provider()).throw(Error);
28
+ expect(() => Provider.instance).throw(Error);
29
+ expect(() => FakeProvider1.instance).not.throw(Error);
30
+ expect(() => FakeProvider2.instance).not.throw(Error);
31
+ expect(() => FakeProvider3.instance).not.throw(Error);
32
+ expect(() => FakeProvider4.instance).not.throw(Error);
33
+ expect(FakeProvider1.instance).equals(FakeProvider1.instance);
34
+ expect(FakeProvider4.instance).equals(FakeProvider4.instance);
35
+ });
36
+
37
+
38
+ it('default getter', () => {
39
+ const provider = FakeProvider1.instance;
40
+ expect(provider.name).equals(FakeProvider1.name);
41
+ expect(provider.displayName).equals(FakeProvider1.name);
42
+ expect(provider.eventsType).is.empty;
43
+ expect(provider.hasNativeInterface).is.false;
44
+ expect(provider.nativeInterface).is.null;
45
+ expect(provider.useCameraNatively).is.false;
46
+ });
47
+
48
+ it('availability', () => {
49
+
50
+ const fakeProvider1 = FakeProvider1.instance;
51
+ expect(fakeProvider1.availability.isSupported).is.true;
52
+ ProvidersOptions.ignoreProviders.push(FakeProvider1.name);
53
+ expect(fakeProvider1.availability.isSupported).is.false;
54
+ expect(fakeProvider1.availability.reason).instanceOf(ContainsIgnoredProviderError);
55
+ ProvidersOptions.ignoreProviders = [];
56
+
57
+ expect(FakeProvider2.instance.availability.isSupported).is.false;
58
+ expect(FakeProvider2.instance.availability.reason).instanceOf(Error);
59
+
60
+ expect(FakeProvider3.instance.availability.isSupported).is.true;
61
+ expect(FakeProvider4.instance.availability.isSupported).is.true;
62
+ });
63
+
64
+ it('checkAvailability on start', () => {
65
+
66
+ const fp2 = FakeProvider2.instance;
67
+
68
+ /**
69
+ * checkAvailabilityOnStart = true
70
+ */
71
+ let errored = false;
72
+ fp2.addEventListener(noop, () => (errored = true));
73
+
74
+ expect(errored).is.true;
75
+ expect(fp2.state).equals(ProviderState.STOPPPED);
76
+ expect(fp2._eventsCallbacks.length).equals(0);
77
+
78
+ /**
79
+ * checkAvailabilityOnStart = false
80
+ */
81
+ ProvidersOptions.checkAvailabilityOnStart = false;
82
+
83
+ errored = false;
84
+ const id = fp2.addEventListener(noop, () => (errored = true));
85
+
86
+ expect(errored).is.false;
87
+ expect(fp2.state).equals(ProviderState.STARTED);
88
+
89
+ fp2.removeEventListener(id);
90
+ expect(fp2.state).equals(ProviderState.STOPPPED);
91
+ expect(fp2._eventsCallbacks.length).equals(0);
92
+
93
+ ProvidersOptions.checkAvailabilityOnStart = true;
94
+ });
95
+
96
+ const startStop = (provider) => {
97
+ return new Promise((resolve, reject) => {
98
+ let isStopped = false;
99
+ let fail = false;
100
+
101
+ const listenerId = provider.addEventListener(() => {
102
+ if (isStopped) {
103
+ fail = true;
104
+ }
105
+ });
106
+
107
+ setTimeout(() => {
108
+ isStopped = true;
109
+ provider.removeEventListener(listenerId);
110
+
111
+ setTimeout(() => {
112
+ if (fail) {
113
+ reject('Provider did not stop');
114
+ } else {
115
+ resolve();
116
+ }
117
+ }, 5);
118
+ }, 7);
119
+ });
120
+ };
121
+
122
+
123
+ it('start/stop', () => {
124
+ expect(() => FakeProvider1.instance.addEventListener()).throw(Error);
125
+
126
+ const idFp5 = FakeProvider5.instance.addEventListener();
127
+ expect(() => FakeProvider5.instance.removeEventListener(idFp5)).throw(Error);
128
+
129
+ return Promise.all([
130
+ expect(startStop(FakeProvider2.instance)).to.be.fulfilled,
131
+ expect(startStop(FakeProvider3.instance)).to.be.fulfilled,
132
+ expect(startStop(FakeProvider4.instance)).to.be.fulfilled
133
+ ]);
134
+ });
135
+
136
+ });
@@ -0,0 +1,5 @@
1
+ export default {
2
+ STARTING: 0,
3
+ STARTED: 1,
4
+ STOPPPED: 2
5
+ };
@@ -0,0 +1,63 @@
1
+ import Provider from '../Provider';
2
+ import EventType from '../../events/EventType';
3
+ import Availability from '../../events/Availability';
4
+ import {
5
+ RelativeAttitude, AbsoluteAttitude
6
+ } from '../../Providers';
7
+
8
+ class AttitudeProvider extends Provider {
9
+
10
+ constructor() {
11
+ super();
12
+ }
13
+
14
+ /**
15
+ * @override
16
+ */
17
+ static get displayName() {
18
+ return 'Attitude';
19
+ }
20
+
21
+ /**
22
+ * @override
23
+ */
24
+ static get eventsType() {
25
+ return [EventType.Attitude];
26
+ }
27
+
28
+ /**
29
+ * @override
30
+ */
31
+ get _availability() {
32
+ return Availability.union(
33
+ RelativeAttitude.availability,
34
+ AbsoluteAttitude.availability
35
+ );
36
+ }
37
+
38
+ /**
39
+ * @override
40
+ */
41
+ start() {
42
+
43
+ if (RelativeAttitude.availability.isSupported) {
44
+ this.provider = RelativeAttitude;
45
+ } else {
46
+ this.provider = AbsoluteAttitude;
47
+ }
48
+
49
+ this.providerId = this.provider.addEventListener(
50
+ events => this.notify(events[0].clone()),
51
+ this.notifyError,
52
+ this.name);
53
+ }
54
+
55
+ /**
56
+ * @override
57
+ */
58
+ stop() {
59
+ this.provider.removeEventListener(this.providerId);
60
+ }
61
+ }
62
+
63
+ export default AttitudeProvider;