@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.
- package/CHANGELOG.md +1 -1
- package/README.md +0 -9
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/AbstractPushHelper.java +1 -1
- package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/AirshipPushHelper.java +1 -1
- package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosLocationReadyListener.java +1 -1
- package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosRegionReadyListener.java +1 -1
- package/android/src/main/java/com/woosmap/reactnativeplugingeofencing/WoosmapGeofencingTurboModule.java +1025 -0
- package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosmapGeofencingTurboPackage.java +3 -7
- package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosmapMessageAndKey.java +2 -3
- package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosmapTask.java +34 -128
- package/android/src/main/java/com/{reactnativeplugingeofencing → woosmap/reactnativeplugingeofencing}/WoosmapUtil.java +1 -1
- package/ios/WoosmapGeofenceMessage.swift +1 -0
- package/ios/WoosmapGeofencingTurbo.mm +110 -10
- package/ios/WoosmapGeofencingTurbo.swift +873 -11
- package/lib/commonjs/NativeWoosmapGeofencingTurbo.js +6 -3
- package/lib/commonjs/NativeWoosmapGeofencingTurbo.js.map +1 -1
- package/lib/commonjs/index.js +37 -131
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/NativeWoosmapGeofencingTurbo.js +6 -3
- package/lib/module/NativeWoosmapGeofencingTurbo.js.map +1 -1
- package/lib/module/index.js +37 -131
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeWoosmapGeofencingTurbo.d.ts +37 -3
- package/lib/typescript/src/NativeWoosmapGeofencingTurbo.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeWoosmapGeofencingTurbo.ts +56 -3
- package/android/src/main/java/com/reactnativeplugingeofencing/PluginGeofencingModule.java +0 -1204
- package/android/src/main/java/com/reactnativeplugingeofencing/PluginGeofencingPackage.java +0 -28
- package/android/src/main/java/com/reactnativeplugingeofencing/WoosmapGeofencingTurboModule.java +0 -185
- package/ios/PluginGeofencing.mm +0 -123
- package/ios/PluginGeofencing.swift +0 -1243
- package/lib/commonjs/internal/nativeInterface.js +0 -13
- package/lib/commonjs/internal/nativeInterface.js.map +0 -1
- package/lib/module/internal/nativeInterface.js +0 -9
- package/lib/module/internal/nativeInterface.js.map +0 -1
- package/lib/typescript/src/internal/nativeInterface.d.ts +0 -3
- package/lib/typescript/src/internal/nativeInterface.d.ts.map +0 -1
- /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
|
+
}
|