@woosmap/react-native-plugin-geofencing 1.0.0-beta.2 → 1.0.0-beta.3

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 (41) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +0 -9
  3. package/android/build.gradle +1 -1
  4. package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/AbstractPushHelper.java +1 -1
  5. package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/AirshipPushHelper.java +1 -1
  6. package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosLocationReadyListener.java +1 -1
  7. package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosRegionReadyListener.java +1 -1
  8. package/android/src/main/java/com/woosmap/reactnativeplugingeofencing/WoosmapGeofencingTurboModule.java +1025 -0
  9. package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosmapGeofencingTurboPackage.java +3 -7
  10. package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosmapMessageAndKey.java +2 -3
  11. package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosmapTask.java +34 -128
  12. package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosmapUtil.java +1 -1
  13. package/ios/WoosmapGeofenceMessage.swift +1 -0
  14. package/ios/WoosmapGeofencingTurbo.mm +110 -10
  15. package/ios/WoosmapGeofencingTurbo.swift +873 -11
  16. package/lib/commonjs/NativeWoosmapGeofencingTurbo.js +6 -3
  17. package/lib/commonjs/NativeWoosmapGeofencingTurbo.js.map +1 -1
  18. package/lib/commonjs/index.js +37 -131
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/module/NativeWoosmapGeofencingTurbo.js +6 -3
  21. package/lib/module/NativeWoosmapGeofencingTurbo.js.map +1 -1
  22. package/lib/module/index.js +37 -131
  23. package/lib/module/index.js.map +1 -1
  24. package/lib/typescript/src/NativeWoosmapGeofencingTurbo.d.ts +37 -3
  25. package/lib/typescript/src/NativeWoosmapGeofencingTurbo.d.ts.map +1 -1
  26. package/lib/typescript/src/index.d.ts +3 -3
  27. package/lib/typescript/src/index.d.ts.map +1 -1
  28. package/package.json +1 -1
  29. package/src/NativeWoosmapGeofencingTurbo.ts +56 -3
  30. package/android/src/main/java/com/reactnativeplugingeofencing/PluginGeofencingModule.java +0 -1204
  31. package/android/src/main/java/com/reactnativeplugingeofencing/PluginGeofencingPackage.java +0 -28
  32. package/android/src/main/java/com/reactnativeplugingeofencing/WoosmapGeofencingTurboModule.java +0 -185
  33. package/ios/PluginGeofencing.mm +0 -123
  34. package/ios/PluginGeofencing.swift +0 -1243
  35. package/lib/commonjs/internal/nativeInterface.js +0 -13
  36. package/lib/commonjs/internal/nativeInterface.js.map +0 -1
  37. package/lib/module/internal/nativeInterface.js +0 -9
  38. package/lib/module/internal/nativeInterface.js.map +0 -1
  39. package/lib/typescript/src/internal/nativeInterface.d.ts +0 -3
  40. package/lib/typescript/src/internal/nativeInterface.d.ts.map +0 -1
  41. /package/ios/{PluginGeofencing-Bridging-Header.h → WoosmapGeofencing-Bridging-Header.h} +0 -0
@@ -0,0 +1,1025 @@
1
+ package com.woosmap.reactnativeplugingeofencing;
2
+
3
+ import android.Manifest;
4
+ import android.app.Activity;
5
+ import android.content.pm.PackageManager;
6
+ import android.os.Build;
7
+ import android.util.Log;
8
+
9
+ import androidx.annotation.NonNull;
10
+ import androidx.annotation.Nullable;
11
+ import androidx.annotation.RequiresApi;
12
+ import androidx.core.app.ActivityCompat;
13
+ import androidx.core.app.NotificationManagerCompat;
14
+
15
+ import com.facebook.react.bridge.Arguments;
16
+ import com.facebook.react.bridge.LifecycleEventListener;
17
+ import com.facebook.react.bridge.Promise;
18
+ import com.facebook.react.bridge.ReactApplicationContext;
19
+ import com.facebook.react.bridge.ReadableArray;
20
+ import com.facebook.react.bridge.ReadableMap;
21
+ import com.facebook.react.bridge.WritableMap;
22
+ import com.facebook.react.module.annotations.ReactModule;
23
+ import com.facebook.react.modules.core.PermissionAwareActivity;
24
+ import com.facebook.react.modules.core.PermissionListener;
25
+ import com.webgeoservices.woosmapgeofencing.NotificationIconProvider;
26
+ import com.webgeoservices.woosmapgeofencing.Woosmap;
27
+ import com.webgeoservices.woosmapgeofencing.WoosmapSettings;
28
+ import com.webgeoservices.woosmapgeofencingcore.database.Region;
29
+ // NativeWoosmapGeofencingTurboSpec (codegen) now lives in this same package
30
+ // (codegenJavaPackageName == this file's package), so no import is needed.
31
+
32
+ import java.io.File;
33
+ import java.io.FileOutputStream;
34
+ import java.io.InputStream;
35
+ import java.net.HttpURLConnection;
36
+ import java.net.URL;
37
+ import java.util.HashMap;
38
+ import java.util.Iterator;
39
+ import java.util.concurrent.ExecutorService;
40
+ import java.util.concurrent.Executors;
41
+
42
+ /**
43
+ * TurboModule implementation for all geofencing methods, including initialization,
44
+ * permissions, watch/clear, and data operations.
45
+ * Extends the codegen-generated {@code NativeWoosmapGeofencingTurboSpec} abstract class.
46
+ */
47
+ @ReactModule(name = WoosmapGeofencingTurboModule.NAME)
48
+ public class WoosmapGeofencingTurboModule extends NativeWoosmapGeofencingTurboSpec
49
+ implements PermissionListener, LifecycleEventListener {
50
+ public static final String NAME = "WoosmapGeofencingTurbo";
51
+
52
+ private final ReactApplicationContext reactContext;
53
+ private Woosmap woosmap;
54
+ private static final int PERMISSIONS_REQUEST_CODE = 150;
55
+ private static final int BLE_PERMISSIONS_REQUEST_CODE = 160;
56
+ private static final int NOTIF_PERMISSIONS_REQUEST_CODE = 170;
57
+ private Promise mPermissionsRequestPromise;
58
+ private Promise mBLEPermissionsRequestPromise;
59
+ private Promise mNotificationPermissionsRequestPromise;
60
+ private WoosLocationReadyListener locationReadyListener;
61
+ private WoosRegionReadyListener regionReadyListener;
62
+ private Woosmap.ProfileReadyListener profileReadyListener;
63
+ private final ExecutorService ioPool = Executors.newSingleThreadExecutor();
64
+
65
+ public WoosmapGeofencingTurboModule(ReactApplicationContext reactContext) {
66
+ super(reactContext);
67
+ this.reactContext = reactContext;
68
+ this.reactContext.addLifecycleEventListener(this);
69
+ }
70
+
71
+ @Override
72
+ @NonNull
73
+ public String getName() {
74
+ return NAME;
75
+ }
76
+
77
+ // ── Lifecycle ─────────────────────────────────────────────────────────────
78
+
79
+ @Override
80
+ public void onHostResume() {
81
+ if (woosmap != null) woosmap.onResume();
82
+ }
83
+
84
+ @Override
85
+ public void onHostPause() {
86
+ if (woosmap != null) woosmap.onPause();
87
+ }
88
+
89
+ @Override
90
+ public void onHostDestroy() {
91
+ if (profileReadyListener != null) {
92
+ woosmap.setProfileReadyListener(null);
93
+ profileReadyListener = null;
94
+ }
95
+ if (woosmap != null) woosmap.onDestroy();
96
+ }
97
+
98
+ // ── Event emitter stubs (required by NativeEventEmitter on JS side) ───────
99
+
100
+ @Override
101
+ public void addListener(String eventName) {}
102
+
103
+ @Override
104
+ public void removeListeners(double count) {}
105
+
106
+ // ── Helpers ───────────────────────────────────────────────────────────────
107
+
108
+ /**
109
+ * Returns whether {@link #initialize(ReadableMap, Promise)} has run. The
110
+ * {@code woosmap} instance field is assigned only inside initialize(), so it
111
+ * is the reliable readiness proxy. {@code Woosmap.getInstance()} must not be
112
+ * used here: it returns the lazily-created singleton even before
113
+ * initializeWoosmap() is called, which would make this guard always true and
114
+ * let callers reach an uninitialized SDK.
115
+ */
116
+ private boolean isWoosmapInitialized() {
117
+ return woosmap != null;
118
+ }
119
+
120
+ private boolean onlyContainsNumbers(String text) {
121
+ try {
122
+ Long.parseLong(text);
123
+ return true;
124
+ } catch (NumberFormatException ex) {
125
+ return false;
126
+ }
127
+ }
128
+
129
+ private boolean onlyContainsDouble(String text) {
130
+ try {
131
+ Double.parseDouble(text);
132
+ return true;
133
+ } catch (NumberFormatException ex) {
134
+ return false;
135
+ }
136
+ }
137
+
138
+ // ── Initialization ────────────────────────────────────────────────────────
139
+
140
+ @Override
141
+ public void initialize(ReadableMap options, Promise promise) {
142
+ String trackingProfile = "";
143
+ try {
144
+ if (options.hasKey(WoosmapMessageAndKey.profileTrackingKey)) {
145
+ String profile = options.getString(WoosmapMessageAndKey.profileTrackingKey);
146
+ if (profile.equals(Woosmap.ConfigurationProfile.liveTracking)) {
147
+ trackingProfile = Woosmap.ConfigurationProfile.liveTracking;
148
+ } else if (profile.equals(Woosmap.ConfigurationProfile.passiveTracking)) {
149
+ trackingProfile = Woosmap.ConfigurationProfile.passiveTracking;
150
+ } else if (profile.equals(Woosmap.ConfigurationProfile.optimalPassiveTracking)) {
151
+ trackingProfile = Woosmap.ConfigurationProfile.optimalPassiveTracking;
152
+ } else if (profile.equals(Woosmap.ConfigurationProfile.visitsTracking)) {
153
+ trackingProfile = Woosmap.ConfigurationProfile.visitsTracking;
154
+ } else if (profile.equals(Woosmap.ConfigurationProfile.beaconTracking)) {
155
+ trackingProfile = Woosmap.ConfigurationProfile.beaconTracking;
156
+ } else {
157
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.invalidProfileTrackingError);
158
+ return;
159
+ }
160
+ }
161
+ woosmap = Woosmap.getInstance().initializeWoosmap(reactContext);
162
+ if (options.hasKey(WoosmapMessageAndKey.woosmapPrivateKeyString)) {
163
+ WoosmapSettings.privateKeyWoosmapAPI = options.getString(WoosmapMessageAndKey.woosmapPrivateKeyString);
164
+ }
165
+ if (options.hasKey(WoosmapMessageAndKey.androidNotificationText)) {
166
+ WoosmapSettings.updateServiceNotificationText = options.getString(WoosmapMessageAndKey.androidNotificationText);
167
+ }
168
+ if (options.hasKey(WoosmapMessageAndKey.androidNotificationTitle)) {
169
+ WoosmapSettings.updateServiceNotificationTitle = options.getString(WoosmapMessageAndKey.androidNotificationTitle);
170
+ }
171
+ if (options.hasKey(WoosmapMessageAndKey.enableAirshipConnectorKey)) {
172
+ WoosmapUtil.setEnableAishipConnector(
173
+ options.getBoolean(WoosmapMessageAndKey.enableAirshipConnectorKey), reactContext);
174
+ }
175
+ // Set the delay of duration data
176
+ WoosmapSettings.numberOfDayDataDuration = 30;
177
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
178
+ this.woosmap.createWoosmapNotifChannel();
179
+ }
180
+ this.woosmap.onResume();
181
+ // Add region listener
182
+ regionReadyListener = new WoosRegionReadyListener(reactContext);
183
+ woosmap.setRegionLogReadyListener(regionReadyListener);
184
+ woosmap.setRegionReadyListener(regionReadyListener);
185
+ if (!trackingProfile.isEmpty()) {
186
+ woosmap.startTracking(trackingProfile);
187
+ }
188
+
189
+ // Notification-icon overrides settle the promise themselves, so resolve
190
+ // here only when no icon override is requested — otherwise the promise
191
+ // would be settled twice (the async URL path is the worst case). A
192
+ // remote URL takes precedence over a resource name when both are set,
193
+ // since both write the same single small-icon override.
194
+ if (options.hasKey(WoosmapMessageAndKey.androidNotificationIconUrl)) {
195
+ NotificationIconProvider.clearRuntimeOverrides(reactContext);
196
+ setNotificationSmallIconByUrl(options.getString(WoosmapMessageAndKey.androidNotificationIconUrl), promise);
197
+ return;
198
+ }
199
+ if (options.hasKey(WoosmapMessageAndKey.androidNotificationIconName)) {
200
+ NotificationIconProvider.clearRuntimeOverrides(reactContext);
201
+ setNotificationSmallIconByName(options.getString(WoosmapMessageAndKey.androidNotificationIconName), promise);
202
+ return;
203
+ }
204
+ promise.resolve(WoosmapMessageAndKey.successMessage);
205
+ } catch (Exception ex) {
206
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
207
+ }
208
+ }
209
+
210
+ private void setNotificationSmallIconByName(String name, Promise promise) {
211
+ try {
212
+ NotificationIconProvider.setRuntimeSmallIconByName(reactContext, name);
213
+ promise.resolve(WoosmapMessageAndKey.successMessage);
214
+ } catch (Throwable ex) {
215
+ promise.reject("EICON", ex);
216
+ }
217
+ }
218
+
219
+ private void setNotificationSmallIconByUrl(String url, Promise promise) {
220
+ try {
221
+ ioPool.execute(() -> {
222
+ try {
223
+ Log.d(NAME, "Saving icon file to local file path");
224
+ String filePath = materializeToCache(url);
225
+ if (filePath == null) {
226
+ Log.e(NAME, "Failed to download/ copy icon");
227
+ promise.reject(WoosmapMessageAndKey.errorCode, "Failed to copy/download icon: " + url);
228
+ return;
229
+ }
230
+ Log.d(NAME, "Saved file path is: " + filePath);
231
+ NotificationIconProvider.setRuntimeSmallIconFromFile(reactContext, filePath);
232
+ promise.resolve(WoosmapMessageAndKey.successMessage);
233
+ } catch (Throwable t) {
234
+ promise.reject(WoosmapMessageAndKey.errorCode, t.toString());
235
+ }
236
+ });
237
+ } catch (Throwable ex) {
238
+ Log.e(NAME, ex.toString());
239
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.toString());
240
+ }
241
+ }
242
+
243
+ private String materializeToCache(String uriString) throws Exception {
244
+ if (uriString == null || uriString.trim().isEmpty()) return null;
245
+
246
+ File dest = new File(reactContext.getCacheDir(), "woosmap_notif_icon.png");
247
+
248
+ if (uriString.startsWith("http://") || uriString.startsWith("https://")) {
249
+ URL url = new URL(uriString);
250
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
251
+ conn.setConnectTimeout(4000);
252
+ conn.setReadTimeout(4000);
253
+ conn.connect();
254
+ try (InputStream is = conn.getInputStream();
255
+ FileOutputStream os = new FileOutputStream(dest)) {
256
+ byte[] buf = new byte[8192];
257
+ int n;
258
+ while ((n = is.read(buf)) > 0) os.write(buf, 0, n);
259
+ } finally {
260
+ conn.disconnect();
261
+ }
262
+ return dest.getAbsolutePath();
263
+ }
264
+
265
+ if (uriString.startsWith("file://")) {
266
+ java.nio.file.Files.copy(
267
+ new File(uriString.substring("file://".length())).toPath(),
268
+ dest.toPath(),
269
+ java.nio.file.StandardCopyOption.REPLACE_EXISTING
270
+ );
271
+ return dest.getAbsolutePath();
272
+ }
273
+
274
+ // content:// and other schemes
275
+ android.net.Uri uri = android.net.Uri.parse(uriString);
276
+ try (InputStream is = reactContext.getContentResolver().openInputStream(uri);
277
+ FileOutputStream os = new FileOutputStream(dest)) {
278
+ if (is == null) return null;
279
+ byte[] buf = new byte[8192];
280
+ int n;
281
+ while ((n = is.read(buf)) > 0) os.write(buf, 0, n);
282
+ return dest.getAbsolutePath();
283
+ }
284
+ }
285
+
286
+ // ── Permissions request ───────────────────────────────────────────────────
287
+
288
+ @Override
289
+ public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
290
+ if (requestCode == PERMISSIONS_REQUEST_CODE && mPermissionsRequestPromise != null) {
291
+ providePermissionStatus(mPermissionsRequestPromise);
292
+ mPermissionsRequestPromise = null;
293
+ }
294
+ if (requestCode == BLE_PERMISSIONS_REQUEST_CODE && mBLEPermissionsRequestPromise != null) {
295
+ provideBLEPermissionStatus(mBLEPermissionsRequestPromise);
296
+ mBLEPermissionsRequestPromise = null;
297
+ }
298
+ if (requestCode == NOTIF_PERMISSIONS_REQUEST_CODE && mNotificationPermissionsRequestPromise != null) {
299
+ provideNotificationPermissionStatus(mNotificationPermissionsRequestPromise);
300
+ mNotificationPermissionsRequestPromise = null;
301
+ }
302
+ return true;
303
+ }
304
+
305
+ @Override
306
+ public void requestPermissions(boolean background, Promise promise) {
307
+ try {
308
+ Activity current = reactContext.getCurrentActivity();
309
+ // No foreground activity to request from: resolve instead of storing the
310
+ // promise, otherwise onRequestPermissionsResult never fires and the
311
+ // promise hangs forever.
312
+ if (!(current instanceof PermissionAwareActivity)) {
313
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
314
+ return;
315
+ }
316
+ PermissionAwareActivity activity = (PermissionAwareActivity) current;
317
+ String[] permissions = (background && Build.VERSION.SDK_INT >= 29)
318
+ ? new String[]{
319
+ Manifest.permission.ACCESS_FINE_LOCATION,
320
+ Manifest.permission.ACCESS_BACKGROUND_LOCATION
321
+ }
322
+ : new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
323
+ // Reject if a request is already pending so we don't overwrite (leak) it.
324
+ if (mPermissionsRequestPromise != null) {
325
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.permissionRequestInProgress);
326
+ return;
327
+ }
328
+ // Assign the pending promise only once a dispatch is guaranteed, so an
329
+ // overlapping call cannot overwrite (and leak) a still-pending promise.
330
+ mPermissionsRequestPromise = promise;
331
+ activity.requestPermissions(permissions, PERMISSIONS_REQUEST_CODE, this);
332
+ } catch (Exception ex) {
333
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
334
+ }
335
+ }
336
+
337
+ @Override
338
+ public void requestBLEPermissions(Promise promise) {
339
+ try {
340
+ if (promise == null) {
341
+ return;
342
+ }
343
+ PermissionAwareActivity activity =
344
+ (PermissionAwareActivity) reactContext.getCurrentActivity();
345
+ if (activity == null) {
346
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
347
+ return;
348
+ }
349
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
350
+ // Reject if a request is already pending so we don't overwrite (leak) it.
351
+ if (mBLEPermissionsRequestPromise != null) {
352
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.permissionRequestInProgress);
353
+ return;
354
+ }
355
+ mBLEPermissionsRequestPromise = promise;
356
+ activity.requestPermissions(
357
+ new String[]{
358
+ Manifest.permission.BLUETOOTH_SCAN,
359
+ Manifest.permission.BLUETOOTH_ADMIN,
360
+ Manifest.permission.BLUETOOTH
361
+ },
362
+ BLE_PERMISSIONS_REQUEST_CODE, this);
363
+ } else {
364
+ promise.resolve(WoosmapMessageAndKey.backgroundPermissionGrantedMessage);
365
+ }
366
+ } catch (Exception ex) {
367
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage(), ex);
368
+ }
369
+ }
370
+
371
+ @Override
372
+ public void requestNotificationPermissions(Promise promise) {
373
+ try {
374
+ Activity activity = reactContext.getCurrentActivity();
375
+ if (activity == null) {
376
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
377
+ return;
378
+ }
379
+ if (Build.VERSION.SDK_INT >= 33) {
380
+ boolean granted = ActivityCompat.checkSelfPermission(
381
+ activity, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
382
+ if (granted && NotificationManagerCompat.from(activity).areNotificationsEnabled()) {
383
+ promise.resolve(WoosmapMessageAndKey.grantedPermissionMessage);
384
+ return;
385
+ }
386
+ // Reject if a request is already pending so we don't overwrite (leak) it.
387
+ if (mNotificationPermissionsRequestPromise != null) {
388
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.permissionRequestInProgress);
389
+ return;
390
+ }
391
+ mNotificationPermissionsRequestPromise = promise;
392
+ ((PermissionAwareActivity) activity).requestPermissions(
393
+ new String[]{Manifest.permission.POST_NOTIFICATIONS},
394
+ NOTIF_PERMISSIONS_REQUEST_CODE, this);
395
+ } else {
396
+ provideNotificationPermissionStatus(promise);
397
+ }
398
+ } catch (Exception ex) {
399
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage(), ex);
400
+ }
401
+ }
402
+
403
+ // ── Permission status helpers ─────────────────────────────────────────────
404
+
405
+ private void providePermissionStatus(final Promise promise) {
406
+ try {
407
+ if (promise == null) {
408
+ return;
409
+ }
410
+ Activity activity = reactContext.getCurrentActivity();
411
+ if (activity == null) {
412
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
413
+ return;
414
+ }
415
+ boolean foreground = ActivityCompat.checkSelfPermission(
416
+ activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
417
+ boolean background = foreground;
418
+ boolean denied = ActivityCompat.shouldShowRequestPermissionRationale(
419
+ activity, Manifest.permission.ACCESS_FINE_LOCATION);
420
+ if (Build.VERSION.SDK_INT >= 29) {
421
+ background = ActivityCompat.checkSelfPermission(
422
+ activity, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED;
423
+ }
424
+ if (background) {
425
+ promise.resolve(WoosmapMessageAndKey.backgroundPermissionGrantedMessage);
426
+ } else if (foreground) {
427
+ promise.resolve(WoosmapMessageAndKey.foregroundPermissionGrantedMessage);
428
+ } else if (denied) {
429
+ promise.resolve(WoosmapMessageAndKey.deniedPermissionMessage);
430
+ } else {
431
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
432
+ }
433
+ } catch (Exception ex) {
434
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
435
+ }
436
+ }
437
+
438
+ private void provideBLEPermissionStatus(final Promise promise) {
439
+ if (promise == null) {
440
+ return;
441
+ }
442
+ Activity activity = reactContext.getCurrentActivity();
443
+ if (activity == null) {
444
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
445
+ return;
446
+ }
447
+ boolean granted = true;
448
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
449
+ granted = ActivityCompat.checkSelfPermission(
450
+ activity, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED;
451
+ }
452
+ if (granted) {
453
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
454
+ granted = ActivityCompat.checkSelfPermission(
455
+ activity, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED;
456
+ }
457
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
458
+ if (granted) {
459
+ granted = ActivityCompat.checkSelfPermission(
460
+ activity, Manifest.permission.BLUETOOTH_ADMIN) == PackageManager.PERMISSION_GRANTED;
461
+ }
462
+ }
463
+ if (granted) {
464
+ promise.resolve(WoosmapMessageAndKey.blePermissionGrantedMessage);
465
+ } else {
466
+ promise.resolve(WoosmapMessageAndKey.deniedPermissionMessage);
467
+ }
468
+ } else {
469
+ promise.resolve(WoosmapMessageAndKey.backgroundPermissionDeniedMessage);
470
+ }
471
+ }
472
+
473
+ private void provideNotificationPermissionStatus(final Promise promise) {
474
+ if (promise == null) return;
475
+ Activity activity = reactContext.getCurrentActivity();
476
+ if (activity == null) {
477
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
478
+ return;
479
+ }
480
+ boolean enabled = NotificationManagerCompat.from(activity).areNotificationsEnabled();
481
+ if (Build.VERSION.SDK_INT >= 33) {
482
+ boolean granted = ActivityCompat.checkSelfPermission(
483
+ activity, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
484
+ if (enabled && granted) {
485
+ promise.resolve(WoosmapMessageAndKey.grantedPermissionMessage);
486
+ } else {
487
+ promise.resolve(WoosmapMessageAndKey.deniedPermissionMessage);
488
+ }
489
+ } else {
490
+ if (enabled) {
491
+ promise.resolve(WoosmapMessageAndKey.grantedPermissionMessage);
492
+ } else {
493
+ promise.resolve(WoosmapMessageAndKey.deniedPermissionMessage);
494
+ }
495
+ }
496
+ }
497
+
498
+ // ── Region CRUD ───────────────────────────────────────────────────────────
499
+
500
+ @Override
501
+ public void setWoosmapApiKey(String apiKey, Promise promise) {
502
+ try {
503
+ if (!isWoosmapInitialized()) {
504
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
505
+ return;
506
+ }
507
+ if (apiKey == null || apiKey.isEmpty()) {
508
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapKeyNotProvide);
509
+ return;
510
+ }
511
+ WoosmapSettings.privateKeyWoosmapAPI = apiKey;
512
+ promise.resolve(WoosmapMessageAndKey.successMessage);
513
+ } catch (Exception ex) {
514
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
515
+ }
516
+ }
517
+
518
+ @Override
519
+ public void setPoiRadius(String radius, Promise promise) {
520
+ try {
521
+ if (!isWoosmapInitialized()) {
522
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
523
+ return;
524
+ }
525
+ if (radius == null || radius.isEmpty()) {
526
+ throw new Exception(WoosmapMessageAndKey.radiusEmptyMessage);
527
+ }
528
+ if (onlyContainsNumbers(radius)) {
529
+ WoosmapSettings.poiRadius = Integer.parseInt(radius);
530
+ } else if (onlyContainsDouble(radius)) {
531
+ WoosmapSettings.poiRadius = (int) Math.round(Double.parseDouble(radius));
532
+ } else {
533
+ WoosmapSettings.poiRadiusNameFromResponse = radius;
534
+ }
535
+ promise.resolve(WoosmapMessageAndKey.successMessage);
536
+ } catch (Exception ex) {
537
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
538
+ }
539
+ }
540
+
541
+ @RequiresApi(api = Build.VERSION_CODES.N)
542
+ @Override
543
+ public void addRegion(ReadableMap region, Promise promise) {
544
+ try {
545
+ if (!isWoosmapInitialized()) {
546
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
547
+ return;
548
+ }
549
+ if (region == null || region.toHashMap().isEmpty()) {
550
+ throw new Exception(WoosmapMessageAndKey.regionInfoEmptyMessage);
551
+ }
552
+ Region woosRegion = new Region();
553
+ woosRegion.identifier = region.getString("regionId");
554
+ woosRegion.idStore = region.hasKey("idStore") ? region.getString("idStore") : "";
555
+ woosRegion.lat = region.getDouble("lat");
556
+ woosRegion.lng = region.getDouble("lng");
557
+ woosRegion.type = region.hasKey("type") ? region.getString("type") : "";
558
+ woosRegion.radius = region.getDouble("radius");
559
+
560
+ WoosmapTask.getInstance(reactContext).addRegion(woosRegion, promise);
561
+ } catch (Exception ex) {
562
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
563
+ }
564
+ }
565
+
566
+ @RequiresApi(api = Build.VERSION_CODES.N)
567
+ @Override
568
+ public void getRegions(@Nullable String regionId, Promise promise) {
569
+ try {
570
+ if (!isWoosmapInitialized()) {
571
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
572
+ return;
573
+ }
574
+ WoosmapTask.getInstance(reactContext).enqueGetRegionsAsArrayRequest(regionId, promise);
575
+ } catch (Exception ex) {
576
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
577
+ }
578
+ }
579
+
580
+ @RequiresApi(api = Build.VERSION_CODES.N)
581
+ @Override
582
+ public void removeRegion(String regionId, Promise promise) {
583
+ try {
584
+ if (!isWoosmapInitialized()) {
585
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
586
+ return;
587
+ }
588
+ if (regionId == null || regionId.isEmpty()) {
589
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.requiredRegionid);
590
+ return;
591
+ }
592
+ WoosmapTask.getInstance(reactContext).removeRegion(regionId, promise);
593
+ } catch (Exception ex) {
594
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
595
+ }
596
+ }
597
+
598
+ @RequiresApi(api = Build.VERSION_CODES.N)
599
+ @Override
600
+ public void removeAllRegions(Promise promise) {
601
+ try {
602
+ if (!isWoosmapInitialized()) {
603
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
604
+ return;
605
+ }
606
+ WoosmapTask.getInstance(reactContext).removeRegion("", promise);
607
+ } catch (Exception ex) {
608
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
609
+ }
610
+ }
611
+
612
+ // ── Tracking ──────────────────────────────────────────────────────────────
613
+
614
+ @Override
615
+ public void startTracking(String profile, Promise promise) {
616
+ try {
617
+ if (!isWoosmapInitialized()) {
618
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
619
+ return;
620
+ }
621
+ if (profile == null || profile.isEmpty()) {
622
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.trackingProfileNotProvided);
623
+ return;
624
+ }
625
+ if (profile.equals(Woosmap.ConfigurationProfile.liveTracking) ||
626
+ profile.equals(Woosmap.ConfigurationProfile.passiveTracking) ||
627
+ profile.equals(Woosmap.ConfigurationProfile.optimalPassiveTracking) ||
628
+ profile.equals(Woosmap.ConfigurationProfile.beaconTracking) ||
629
+ profile.equals(Woosmap.ConfigurationProfile.visitsTracking)) {
630
+ Woosmap.getInstance().startTracking(profile);
631
+ promise.resolve(WoosmapMessageAndKey.successMessage);
632
+ } else {
633
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.invalidProfileTrackingError);
634
+ }
635
+ } catch (Exception ex) {
636
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
637
+ }
638
+ }
639
+
640
+ @Override
641
+ public void stopTracking(Promise promise) {
642
+ try {
643
+ if (!isWoosmapInitialized()) {
644
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
645
+ return;
646
+ }
647
+ Woosmap.getInstance().stopTracking();
648
+ promise.resolve(WoosmapMessageAndKey.successMessage);
649
+ } catch (Exception ex) {
650
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
651
+ }
652
+ }
653
+
654
+ @Override
655
+ public void startCustomTracking(String mode, String source, Promise promise) {
656
+ try {
657
+ if (!isWoosmapInitialized()) {
658
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
659
+ return;
660
+ }
661
+ if (!mode.equalsIgnoreCase(WoosmapMessageAndKey.localMode) &&
662
+ !mode.equalsIgnoreCase(WoosmapMessageAndKey.externalMode)) {
663
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.invalidProfileSourceType);
664
+ return;
665
+ }
666
+ // Store in the field (not a local) so onHostDestroy can detach it from
667
+ // the Woosmap singleton, which outlives this module instance.
668
+ profileReadyListener = (status, errors) -> {
669
+ try {
670
+ if (status) {
671
+ promise.resolve(WoosmapMessageAndKey.successMessage);
672
+ } else {
673
+ promise.reject(WoosmapMessageAndKey.errorCode, errors.get(0));
674
+ }
675
+ } catch (Exception ex) {
676
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
677
+ }
678
+ };
679
+ Woosmap.getInstance().setProfileReadyListener(profileReadyListener);
680
+ Woosmap.getInstance().startCustomTracking(source);
681
+ } catch (Exception ex) {
682
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
683
+ }
684
+ }
685
+
686
+ // ── Watch / clear ─────────────────────────────────────────────────────────
687
+
688
+ @Override
689
+ public void watchLocation(String watchID, Promise promise) {
690
+ try {
691
+ if (!isWoosmapInitialized()) {
692
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
693
+ return;
694
+ }
695
+ if (locationReadyListener == null) {
696
+ locationReadyListener = new WoosLocationReadyListener(reactContext);
697
+ Woosmap.getInstance().setLocationReadyListener(locationReadyListener);
698
+ promise.resolve(watchID);
699
+ } else {
700
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.locationWatchAlreadyStarted);
701
+ }
702
+ } catch (Exception ex) {
703
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
704
+ }
705
+ }
706
+
707
+ @Override
708
+ public void clearLocationWatch(String watchID, Promise promise) {
709
+ try {
710
+ if (locationReadyListener != null) {
711
+ Woosmap.getInstance().setLocationReadyListener(null);
712
+ locationReadyListener = null;
713
+ promise.resolve(watchID);
714
+ } else {
715
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.locationWatchNotStarted);
716
+ }
717
+ } catch (Exception ex) {
718
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
719
+ }
720
+ }
721
+
722
+ @Override
723
+ public void clearAllLocationWatch(Promise promise) {
724
+ try {
725
+ Woosmap.getInstance().setLocationReadyListener(null);
726
+ locationReadyListener = null;
727
+ promise.resolve("00000-00000-0000");
728
+ } catch (Exception ex) {
729
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
730
+ }
731
+ }
732
+
733
+ @Override
734
+ public void watchRegions(String watchID, Promise promise) {
735
+ try {
736
+ if (!isWoosmapInitialized()) {
737
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
738
+ return;
739
+ }
740
+ if (regionReadyListener == null) {
741
+ regionReadyListener = new WoosRegionReadyListener(reactContext);
742
+ Woosmap.getInstance().setRegionLogReadyListener(regionReadyListener);
743
+ Woosmap.getInstance().setRegionReadyListener(regionReadyListener);
744
+ }
745
+ if (!regionReadyListener.getIsRegionWatchEnabled()) {
746
+ regionReadyListener.setIsRegionWatchEnabled(true);
747
+ promise.resolve(watchID);
748
+ } else {
749
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.regionWatchAlreadyStarted);
750
+ }
751
+ } catch (Exception ex) {
752
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
753
+ }
754
+ }
755
+
756
+ @Override
757
+ public void clearRegionsWatch(String watchID, Promise promise) {
758
+ try {
759
+ if (regionReadyListener != null && regionReadyListener.getIsRegionWatchEnabled()) {
760
+ regionReadyListener.setIsRegionWatchEnabled(false);
761
+ promise.resolve(watchID);
762
+ } else {
763
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.regionWatchNotStarted);
764
+ }
765
+ } catch (Exception ex) {
766
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
767
+ }
768
+ }
769
+
770
+ @Override
771
+ public void clearAllRegionsWatch(Promise promise) {
772
+ try {
773
+ if (regionReadyListener != null) {
774
+ regionReadyListener.setIsRegionWatchEnabled(false);
775
+ }
776
+ promise.resolve("00000-00000-0000");
777
+ } catch (Exception ex) {
778
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
779
+ }
780
+ }
781
+
782
+ // ── Permission status ─────────────────────────────────────────────────────
783
+
784
+ @Override
785
+ public void getPermissionsStatus(Promise promise) {
786
+ try {
787
+ Activity activity = reactContext.getCurrentActivity();
788
+ if (activity == null) {
789
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
790
+ return;
791
+ }
792
+ boolean foreground = ActivityCompat.checkSelfPermission(activity,
793
+ Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
794
+ boolean background = foreground;
795
+ boolean denied = ActivityCompat.shouldShowRequestPermissionRationale(activity,
796
+ Manifest.permission.ACCESS_FINE_LOCATION);
797
+
798
+ if (Build.VERSION.SDK_INT >= 29) {
799
+ background = ActivityCompat.checkSelfPermission(activity,
800
+ Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED;
801
+ }
802
+
803
+ if (background) {
804
+ promise.resolve(WoosmapMessageAndKey.backgroundPermissionGrantedMessage);
805
+ } else if (foreground) {
806
+ promise.resolve(WoosmapMessageAndKey.foregroundPermissionGrantedMessage);
807
+ } else if (denied) {
808
+ promise.resolve(WoosmapMessageAndKey.deniedPermissionMessage);
809
+ } else {
810
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
811
+ }
812
+ } catch (Exception ex) {
813
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
814
+ }
815
+ }
816
+
817
+ @Override
818
+ public void getBLEPermissionsStatus(Promise promise) {
819
+ try {
820
+ Activity activity = reactContext.getCurrentActivity();
821
+ if (activity == null) {
822
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
823
+ return;
824
+ }
825
+ boolean granted = true;
826
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
827
+ granted = ActivityCompat.checkSelfPermission(activity,
828
+ Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED;
829
+ }
830
+ if (granted && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
831
+ granted = ActivityCompat.checkSelfPermission(activity,
832
+ Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED
833
+ && ActivityCompat.checkSelfPermission(activity,
834
+ Manifest.permission.BLUETOOTH_ADMIN) == PackageManager.PERMISSION_GRANTED;
835
+ }
836
+ if (granted) {
837
+ promise.resolve(WoosmapMessageAndKey.blePermissionGrantedMessage);
838
+ } else {
839
+ promise.resolve(WoosmapMessageAndKey.deniedPermissionMessage);
840
+ }
841
+ } catch (Exception ex) {
842
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
843
+ }
844
+ }
845
+
846
+ @Override
847
+ public void getNotificationPermissionsStatus(Promise promise) {
848
+ try {
849
+ Activity activity = reactContext.getCurrentActivity();
850
+ if (activity == null) {
851
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
852
+ return;
853
+ }
854
+ boolean enabled = NotificationManagerCompat.from(activity).areNotificationsEnabled();
855
+ if (Build.VERSION.SDK_INT >= 33) {
856
+ boolean granted = ActivityCompat.checkSelfPermission(activity,
857
+ Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
858
+ promise.resolve((enabled && granted)
859
+ ? WoosmapMessageAndKey.grantedPermissionMessage
860
+ : WoosmapMessageAndKey.deniedPermissionMessage);
861
+ } else {
862
+ promise.resolve(enabled
863
+ ? WoosmapMessageAndKey.grantedPermissionMessage
864
+ : WoosmapMessageAndKey.deniedPermissionMessage);
865
+ }
866
+ } catch (Exception ex) {
867
+ promise.resolve(WoosmapMessageAndKey.unknownMessage);
868
+ }
869
+ }
870
+
871
+ // ── Configuration ─────────────────────────────────────────────────────────
872
+
873
+ @Override
874
+ public void setSFMCCredentials(ReadableMap credentials, Promise promise) {
875
+ try {
876
+ if (!isWoosmapInitialized()) {
877
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
878
+ return;
879
+ }
880
+ if (credentials == null || credentials.toHashMap().isEmpty()) {
881
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.credentialEmptyMessage);
882
+ return;
883
+ }
884
+ String[] required = {
885
+ WoosmapMessageAndKey.SMFCauthenticationBaseURIkey,
886
+ WoosmapMessageAndKey.SMFCrestBaseURIkey,
887
+ WoosmapMessageAndKey.SMFCclient_idkey,
888
+ WoosmapMessageAndKey.SMFCclient_secretkey,
889
+ WoosmapMessageAndKey.SMFCcontactKey
890
+ };
891
+ for (String key : required) {
892
+ if (!credentials.hasKey(key)) {
893
+ throw new Exception(WoosmapMessageAndKey.keyMissingMessage + ": " + key);
894
+ }
895
+ }
896
+ HashMap<String, String> sfmcInfo = new HashMap<>();
897
+ Iterator<String> keys = credentials.toHashMap().keySet().iterator();
898
+ while (keys.hasNext()) {
899
+ String key = keys.next();
900
+ sfmcInfo.put(key, credentials.getString(key));
901
+ }
902
+ WoosmapSettings.SFMCCredentials = sfmcInfo;
903
+ promise.resolve(WoosmapMessageAndKey.successMessage);
904
+ } catch (Exception ex) {
905
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
906
+ }
907
+ }
908
+
909
+ @Override
910
+ public void setProtectedRegionSlot(double slots, Promise promise) {
911
+ // No-op on Android: protected region slots are an iOS-only concept.
912
+ promise.resolve(WoosmapMessageAndKey.successMessage);
913
+ }
914
+
915
+ // ── Data queries ──────────────────────────────────────────────────────────
916
+
917
+ @RequiresApi(api = Build.VERSION_CODES.N)
918
+ @Override
919
+ public void getLocations(@Nullable String locationId, Promise promise) {
920
+ try {
921
+ if (!isWoosmapInitialized()) {
922
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
923
+ return;
924
+ }
925
+ WoosmapTask.getInstance(reactContext).enqueueGetLocationsAsArrayRequest(locationId, promise);
926
+ } catch (Exception ex) {
927
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
928
+ }
929
+ }
930
+
931
+ @RequiresApi(api = Build.VERSION_CODES.N)
932
+ @Override
933
+ public void getPois(@Nullable String poiId, Promise promise) {
934
+ try {
935
+ if (!isWoosmapInitialized()) {
936
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
937
+ return;
938
+ }
939
+ WoosmapTask.getInstance(reactContext).enqueueGetPoisAsArrayRequest(poiId, promise);
940
+ } catch (Exception ex) {
941
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
942
+ }
943
+ }
944
+
945
+ @RequiresApi(api = Build.VERSION_CODES.N)
946
+ @Override
947
+ public void getIndoorBeacons(@Nullable String venueId, Promise promise) {
948
+ try {
949
+ if (!isWoosmapInitialized()) {
950
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
951
+ return;
952
+ }
953
+ WoosmapTask.getInstance(reactContext).enqueueGetIndoorBeaconRequest(venueId, promise);
954
+ } catch (Exception ex) {
955
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
956
+ }
957
+ }
958
+
959
+ // ── Data removal ──────────────────────────────────────────────────────────
960
+
961
+ @RequiresApi(api = Build.VERSION_CODES.N)
962
+ @Override
963
+ public void removeLocations(Promise promise) {
964
+ try {
965
+ if (!isWoosmapInitialized()) {
966
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
967
+ return;
968
+ }
969
+ WoosmapTask.getInstance(reactContext).removeAllLocation(promise);
970
+ } catch (Exception ex) {
971
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
972
+ }
973
+ }
974
+
975
+ @RequiresApi(api = Build.VERSION_CODES.N)
976
+ @Override
977
+ public void removePois(Promise promise) {
978
+ try {
979
+ if (!isWoosmapInitialized()) {
980
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
981
+ return;
982
+ }
983
+ WoosmapTask.getInstance(reactContext).removeAllPois(promise);
984
+ } catch (Exception ex) {
985
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
986
+ }
987
+ }
988
+
989
+ @RequiresApi(api = Build.VERSION_CODES.N)
990
+ @Override
991
+ public void removeIndoorBeacons(Promise promise) {
992
+ try {
993
+ if (!isWoosmapInitialized()) {
994
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
995
+ return;
996
+ }
997
+ WoosmapTask.getInstance(reactContext).removeAllBeacons(promise);
998
+ } catch (Exception ex) {
999
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
1000
+ }
1001
+ }
1002
+
1003
+ @Override
1004
+ public void refreshPois(Promise promise) {
1005
+ try {
1006
+ if (!isWoosmapInitialized()) {
1007
+ promise.reject(WoosmapMessageAndKey.errorCode, WoosmapMessageAndKey.woosmapNotInitialized);
1008
+ return;
1009
+ }
1010
+ Woosmap.getInstance().refreshPOIs(new Woosmap.POIRefreshCallback() {
1011
+ @Override
1012
+ public void onPOIsRefreshed() {
1013
+ promise.resolve(WoosmapMessageAndKey.successMessage);
1014
+ }
1015
+
1016
+ @Override
1017
+ public void onError(String error) {
1018
+ promise.reject(new Exception(error));
1019
+ }
1020
+ });
1021
+ } catch (Exception ex) {
1022
+ promise.reject(WoosmapMessageAndKey.errorCode, ex.getMessage());
1023
+ }
1024
+ }
1025
+ }