Skip to content

Commit

Permalink
Radio scan callbacks (#70)
Browse files Browse the repository at this point in the history
NOTE! To enable the callbacks, please contact IndoorAtlas support.
  • Loading branch information
matti-ida authored May 13, 2024
1 parent c68738c commit 0f85ce2
Show file tree
Hide file tree
Showing 10 changed files with 529 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.gradle
6 changes: 6 additions & 0 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
<js-module src="www/POI.js" name="POI">
<clobbers target="IndoorAtlas.POI"/>
</js-module>
<js-module src="www/RadioScan.js" name="RadioScan">
<clobbers target="IndoorAtlas.RadioScan"/>
</js-module>
<js-module src="www/IndoorAtlas.js" name="IndoorAtlas">
<merges target="IndoorAtlas"/>
</js-module>
Expand All @@ -57,6 +60,9 @@
<config-file target="*-Info.plist" parent="NSLocationWhenInUseUsageDescription">
<string>Platform location requested for better indoor positioning experience.</string>
</config-file>
<config-file target="*-Info.plist" parent="NSMotionUsageDescription">
<string>Device motion requested for better indoor positioning experience.</string>
</config-file>
<framework src="CFNetwork.framework"/>
<framework src="CoreLocation.framework"/>
<framework src="CoreMotion.framework"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.indooratlas.android.sdk.IARoute;
import com.indooratlas.android.sdk.IAOrientationRequest;
import com.indooratlas.android.sdk.IAOrientationListener;
import com.indooratlas.android.sdk.IARadioScanRequest;
import com.indooratlas.android.sdk.IAWayfindingListener;
import com.indooratlas.android.sdk.IAWayfindingRequest;
import com.indooratlas.android.sdk.IAGeofence;
Expand Down Expand Up @@ -63,6 +64,7 @@ public class IALocationPlugin extends CordovaPlugin {
private boolean mLocationServiceRunning = false;
private IALocationRequest mLocationRequest = IALocationRequest.create();
private IAOrientationRequest mOrientationRequest = new IAOrientationRequest(1.0, 1.0);
private IARadioScanRequest mRadioScanRequest = null;

/**
* Called by the WebView implementation to check for geolocation permissions, can be used
Expand Down Expand Up @@ -244,6 +246,14 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
} else if ("lockIndoors".equals(action)) {
boolean locked = args.getBoolean(0);
lockIndoors(locked);
} else if ("watchIBeacons".equals(action)) {
watchIBeacons(callbackContext);
} else if ("clearIBeaconWatch".equals(action)) {
clearIBeaconWatch();
} else if ("watchWifis".equals(action)) {
watchWifis(callbackContext);
} else if ("clearWifiWatch".equals(action)) {
clearWifiWatch();
}
}
catch(Exception ex) {
Expand Down Expand Up @@ -634,6 +644,78 @@ public void run() {
}
}

private void watchIBeacons(CallbackContext callbackContext) {
final IARadioScanRequest req = (mRadioScanRequest != null && mRadioScanRequest.wifis) ?
mRadioScanRequest.andIBeacons() : IARadioScanRequest.withIBeacons();
mRadioScanRequest = req;
getListener(this).addIBeaconWatch(callbackContext);
cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mLocationManager.requestRadioScanUpdates(
req,
getListener(IALocationPlugin.this)
);
}
});
}

private void clearIBeaconWatch() {
final IARadioScanRequest req = (mRadioScanRequest != null && mRadioScanRequest.wifis) ?
IARadioScanRequest.withWifis() : null;
mRadioScanRequest = req;
getListener(this).clearIBeaconWatch();
cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (req == null) {
mLocationManager.removeRadioScanUpdates();
} else {
mLocationManager.requestRadioScanUpdates(
req,
getListener(IALocationPlugin.this)
);
}
}
});
}

private void watchWifis(CallbackContext callbackContext) {
final IARadioScanRequest req = (mRadioScanRequest != null && mRadioScanRequest.iBeacons) ?
mRadioScanRequest.andWifis() : IARadioScanRequest.withWifis();
mRadioScanRequest = req;
getListener(this).addWifiWatch(callbackContext);
cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mLocationManager.requestRadioScanUpdates(
req,
getListener(IALocationPlugin.this)
);
}
});
}

private void clearWifiWatch() {
final IARadioScanRequest req = (mRadioScanRequest != null && mRadioScanRequest.iBeacons) ?
IARadioScanRequest.withIBeacons() : null;
mRadioScanRequest = req;
getListener(this).clearWifiWatch();
cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (req == null) {
mLocationManager.removeRadioScanUpdates();
} else {
mLocationManager.requestRadioScanUpdates(
req,
getListener(IALocationPlugin.this)
);
}
}
});
}

/**
* Starts IndoorAtlas positioning session
* @param callbackContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import com.indooratlas.android.sdk.IARegion;
import com.indooratlas.android.sdk.IARoute;
import com.indooratlas.android.sdk.IAOrientationListener;
import com.indooratlas.android.sdk.IARadioScanListener;
import com.indooratlas.android.sdk.IAWayfindingListener;
import com.indooratlas.android.sdk.IAGeofence;
import com.indooratlas.android.sdk.IAGeofenceEvent;
import com.indooratlas.android.sdk.IAGeofenceListener;
import com.indooratlas.android.sdk.IAPOI;
import com.indooratlas.android.sdk.resources.IAFloorPlan;
import com.indooratlas.android.sdk.resources.IALatLng;
import com.indooratlas.android.sdk.resources.IARadioScan;
import com.indooratlas.android.sdk.resources.IAVenue;

import org.apache.cordova.CallbackContext;
Expand All @@ -26,11 +28,12 @@

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
* Handles events from IALocationListener and IARegion.Listener and relays them to Javascript callbacks.
*/
public class IndoorLocationListener implements IALocationListener, IARegion.Listener, IAOrientationListener,
public class IndoorLocationListener extends IARadioScanListener implements IALocationListener, IARegion.Listener, IAOrientationListener,
IAWayfindingListener, IAGeofenceListener {
private static final String TAG = "IndoorLocationListener";

Expand All @@ -45,6 +48,8 @@ public class IndoorLocationListener implements IALocationListener, IARegion.List
private CallbackContext statusUpdateCallbackContext;
private CallbackContext wayfindingUpdateCallbackContext;
private CallbackContext geofenceCallbackContext;
private CallbackContext iBeaconScanCallbackContext;
private CallbackContext wifiScanCallbackContext;
private ArrayList<CallbackContext> mCallbacks = new ArrayList<CallbackContext>();
private CallbackContext mCallbackContext;
public IALocation lastKnownLocation = null;
Expand Down Expand Up @@ -148,6 +153,22 @@ public void removeGeofenceUpdates() {
geofenceCallbackContext = null;
}

public void addIBeaconWatch(CallbackContext callbackContext) {
iBeaconScanCallbackContext = callbackContext;
}

public void clearIBeaconWatch() {
iBeaconScanCallbackContext = null;
}

public void addWifiWatch(CallbackContext callbackContext) {
wifiScanCallbackContext = callbackContext;
}

public void clearWifiWatch() {
wifiScanCallbackContext = null;
}

/**
* Returns the sum of the all callback collections
* @return
Expand Down Expand Up @@ -684,4 +705,99 @@ public void onGeofencesTriggered(IAGeofenceEvent event) {
}
}
}
}

@Override
public void onIBeaconScan​(List<IARadioScan.IBeacon> beacons) {
if (iBeaconScanCallbackContext != null) {
try {
JSONArray scans = new JSONArray();
for (IARadioScan.IBeacon beacon : beacons) {
JSONObject scan = new JSONObject();
scan.put("uuid", beacon.uuid.toString().toLowerCase());
scan.put("major", beacon.major);
scan.put("minor", beacon.minor);
scan.put("rssi", beacon.rssi);
scans.put(scan);
}
JSONObject result = new JSONObject();
result.put("beacons", scans);
PluginResult pluginResult = new PluginResult(
PluginResult.Status.OK,
result
);
pluginResult.setKeepCallback(true);
iBeaconScanCallbackContext.sendPluginResult(pluginResult);
} catch (JSONException e) {
throw new IllegalStateException(e.getMessage());
}
}
}

@Override
public void onIBeaconScanError​(int errorCode, String description) {
if (iBeaconScanCallbackContext != null) {
try {
JSONObject details = new JSONObject();
details.put("errorCode", errorCode);
JSONObject error = new JSONObject();
error.put("description", description);
error.put("details", details);
JSONObject result = new JSONObject();
result.put("error", error);
PluginResult pluginResult = new PluginResult(
PluginResult.Status.OK,
result
);
pluginResult.setKeepCallback(true);
iBeaconScanCallbackContext.sendPluginResult(pluginResult);
} catch (JSONException e) {
throw new IllegalStateException(e.getMessage());
}
}
}

@Override
public void onWifiScan​(List<IARadioScan.Wifi> wifis) {
if (wifiScanCallbackContext != null) {
try {
JSONArray scans = new JSONArray();
for (IARadioScan.Wifi wifi : wifis) {
JSONObject scan = new JSONObject();
scan.put("bssid", wifi.bssid);
scan.put("rssi", wifi.rssi);
scans.put(scan);
}
JSONObject result = new JSONObject();
result.put("wifis", scans);
PluginResult pluginResult = new PluginResult(
PluginResult.Status.OK,
result
);
pluginResult.setKeepCallback(true);
wifiScanCallbackContext.sendPluginResult(pluginResult);
} catch (JSONException e) {
throw new IllegalStateException(e.getMessage());
}
}
}

@Override
public void onWifiScanError() {
if (wifiScanCallbackContext != null) {
try {
JSONObject error = new JSONObject();
error.put("description", "wifi scan failed");
JSONObject result = new JSONObject();
result.put("error", error);
PluginResult pluginResult = new PluginResult(
PluginResult.Status.OK,
result
);
pluginResult.setKeepCallback(true);
wifiScanCallbackContext.sendPluginResult(pluginResult);
} catch (JSONException e) {
throw new IllegalStateException(e.getMessage());
}
}
}
}
8 changes: 8 additions & 0 deletions src/ios/IndoorAtlasLocationService.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ typedef NSUInteger IndoorLocationTransitionType;
*/
- (void)location:(IndoorAtlasLocationService *)manager didUpdateRoute:(nonnull IARoute *)route;

- (void)location:(IndoorAtlasLocationService *)manager didRangeBeacons:(nonnull NSArray<CLBeacon *> *)beacons;

- (void)location:(IndoorAtlasLocationService *)manager rangingBeaconsDidFailForRegion:(nonnull CLBeaconRegion *)region
withError:(nonnull NSError *)error;

@end
@interface IndoorAtlasLocationService : NSObject{

Expand Down Expand Up @@ -129,6 +134,9 @@ typedef NSUInteger IndoorLocationTransitionType;
- (void)startMonitoringGeofences:(IAGeofence *)geofence;
- (void)stopMonitoringGeofences:(IAGeofence *)geofence;

- (void)startMonitoringForBeacons;
- (void)stopMonitoringForBeacons;

- (void)valueForDistanceFilter:(float *)distance;
- (void)valueForTimeFilter:(float *)interval;
- (void)setDesiredAccuracy:(ia_location_accuracy)accuracy;
Expand Down
27 changes: 27 additions & 0 deletions src/ios/IndoorAtlasLocationService.m
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,21 @@ - (void)indoorLocationManager:(IALocationManager *)manager didUpdateRoute:(nonnu
}
}

- (void)indoorLocationManager:(nonnull IALocationManager *)manager didRangeBeacons:(nonnull NSArray<CLBeacon *> *)beacons
{
if([self.delegate respondsToSelector:@selector(location:didRangeBeacons:)]) {
[self.delegate location:self didRangeBeacons:beacons];
}
}

- (void)indoorLocationManager:(nonnull IALocationManager *)manager rangingBeaconsDidFailForRegion:(nonnull CLBeaconRegion *)region
withError:(nonnull NSError *)error
{
if([self.delegate respondsToSelector:@selector(location:rangingBeaconsDidFailForRegion:withError:)]) {
[self.delegate location:self rangingBeaconsDidFailForRegion:region withError:error];
}
}

- (void)valueForDistanceFilter:(float *)distance
{
self.manager.distanceFilter = (CLLocationDistance) *(distance);
Expand Down Expand Up @@ -271,4 +286,16 @@ - (void)stopMonitoringGeofences:(IAGeofence *)geofence
[self.manager stopMonitoringForGeofence:geofence];
}

- (void)startMonitoringForBeacons
{
NSLog(@"startMonitoringForBeacons");
[self.manager startMonitoringForBeacons];
}

- (void)stopMonitoringForBeacons
{
NSLog(@"stopMonitoringForBeacons");
[self.manager stopMonitoringForBeacons];
}

@end
2 changes: 2 additions & 0 deletions src/ios/IndoorLocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,6 @@ typedef NSUInteger IndoorLocationStatus;
- (void)lockFloor:(CDVInvokedUrlCommand *)command;
- (void)unlockFloor:(CDVInvokedUrlCommand *)command;
- (void)lockIndoors:(CDVInvokedUrlCommand *)command;
- (void)watchIBeacons:(CDVInvokedUrlCommand *)command;
- (void)clearIBeaconWatch:(CDVInvokedUrlCommand *)command;
@end
Loading

0 comments on commit 0f85ce2

Please sign in to comment.