Commit 43acaf0f authored by Chris Scott's avatar Chris Scott

Merge branch 'trigger-activities' into edge

parents d6319eb3 72ef5aa7
......@@ -268,6 +268,23 @@ Disable background geolocation tracking.
bgGeo.stop();
```
####`getCurrentPosition(successFn, failureFn)`
Retrieves the current position. This method instructs the native code to fetch exactly one location using maximum power & accuracy. The native code will persist the fetched location to SQLite just as any other location in addition to POSTing to your configured `#url` (if you've enabled the HTTP features). In addition to your supplied `callbackFn`, the plugin will also execute the `callback` provided to `#configure`. Your provided `successFn` will be executed with the same signature as that provided to `#configure`:
######@param {Object} location The Location data
######@param {Integer} taskId The taskId used to send to bgGeo.finish(taskId) in order to signal completion of your callbackFn
```
bgGeo.getCurrentPosition(function(location, taskId) {
// This location is already persisted to plugin’s SQLite db.
// If you’ve configured #autoSync: true, the HTTP POST has already started.
console.log(“- Current position received: “, location);
bgGeo.finish(taskId);
});
```
####`changePace(enabled, successFn, failureFn)`
Initiate or cancel immediate background tracking. When set to ```true```, the plugin will begin aggressively tracking the devices Geolocation, bypassing stationary monitoring. If you were making a "Jogging" application, this would be your [Start Workout] button to immediately begin GPS tracking. Send ```false``` to disable aggressive GPS monitoring and return to stationary-monitoring mode.
......
......@@ -28,32 +28,42 @@ import android.media.AudioManager;
import android.media.ToneGenerator;
public class CDVBackgroundGeolocation extends CordovaPlugin {
private static final String TAG = "BackgroundGeolocation";
private static final String TAG = "TSLocationManager";
private static CordovaWebView gWebView;
public static Boolean forceReload = false;
/**
* Timeout in millis for a getCurrentPosition request to give up.
* TODO make configurable.
*/
private static final long GET_CURRENT_POSITION_TIMEOUT = 30000;
public static final String ACTION_START = "start";
public static final String ACTION_STOP = "stop";
public static final String ACTION_FINISH = "finish";
public static final String ACTION_ERROR = "error";
public static final String ACTION_ON_PACE_CHANGE = "onPaceChange";
public static final String ACTION_CONFIGURE = "configure";
public static final String ACTION_SET_CONFIG = "setConfig";
public static final String ACTION_ON_STATIONARY = "addStationaryRegionListener";
public static final String ACTION_GET_LOCATIONS = "getLocations";
public static final String ACTION_SYNC = "sync";
public static final String ACTION_GET_ODOMETER = "getOdometer";
public static final String ACTION_RESET_ODOMETER = "resetOdometer";
public static final String ACTION_ADD_GEOFENCE = "addGeofence";
public static final String ACTION_REMOVE_GEOFENCE = "removeGeofence";
public static final String ACTION_GET_GEOFENCES = "getGeofences";
public static final String ACTION_ON_GEOFENCE = "onGeofence";
public static final String ACTION_PLAY_SOUND = "playSound";
public static final String ACTION_START = "start";
public static final String ACTION_STOP = "stop";
public static final String ACTION_FINISH = "finish";
public static final String ACTION_ERROR = "error";
public static final String ACTION_CHANGE_PACE = "changePace";
public static final String ACTION_CONFIGURE = "configure";
public static final String ACTION_SET_CONFIG = "setConfig";
public static final String ACTION_ON_STATIONARY = "addStationaryRegionListener";
public static final String ACTION_ADD_MOTION_CHANGE_LISTENER = "addMotionChangeListener";
public static final String ACTION_ON_MOTION_CHANGE = "onMotionChange";
public static final String ACTION_GET_LOCATIONS = "getLocations";
public static final String ACTION_SYNC = "sync";
public static final String ACTION_GET_ODOMETER = "getOdometer";
public static final String ACTION_RESET_ODOMETER = "resetOdometer";
public static final String ACTION_ADD_GEOFENCE = "addGeofence";
public static final String ACTION_REMOVE_GEOFENCE = "removeGeofence";
public static final String ACTION_GET_GEOFENCES = "getGeofences";
public static final String ACTION_ON_GEOFENCE = "onGeofence";
public static final String ACTION_PLAY_SOUND = "playSound";
public static final String ACTION_ACTIVITY_RELOAD = "activityReload";
private Boolean isEnabled = false;
private Boolean stopOnTerminate = false;
private Boolean isMoving = false;
private Boolean isAcquiringCurrentPosition = false;
private long isAcquiringCurrentPositionSince;
private Intent backgroundServiceIntent;
private DetectedActivity currentActivity;
......@@ -70,7 +80,9 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
private ToneGenerator toneGenerator;
private List<CallbackContext> motionChangeCallbacks = new ArrayList<CallbackContext>();
private List<CallbackContext> geofenceCallbacks = new ArrayList<CallbackContext>();
private List<CallbackContext> currentPositionCallbacks = new ArrayList<CallbackContext>();
public static boolean isActive() {
return gWebView != null;
......@@ -91,15 +103,15 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
Boolean result = false;
if (ACTION_START.equalsIgnoreCase(action) && !isEnabled) {
if (ACTION_START.equalsIgnoreCase(action)) {
result = true;
this.setEnabled(true);
callbackContext.success();
callbackContext.success(1);
} else if (ACTION_STOP.equalsIgnoreCase(action)) {
// No implementation to stop background-tasks with Android. Just say "success"
result = true;
this.setEnabled(false);
callbackContext.success();
callbackContext.success(0);
} else if (ACTION_FINISH.equalsIgnoreCase(action)) {
result = true;
callbackContext.success();
......@@ -114,7 +126,7 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
} else {
callbackContext.error("- Configuration error!");
}
} else if (ACTION_ON_PACE_CHANGE.equalsIgnoreCase(action)) {
} else if (BackgroundGeolocationService.ACTION_CHANGE_PACE.equalsIgnoreCase(action)) {
if (!isEnabled) {
Log.w(TAG, "- Cannot change pace while disabled");
result = false;
......@@ -142,6 +154,9 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
} else if (ACTION_ON_STATIONARY.equalsIgnoreCase(action)) {
result = true;
this.stationaryCallback = callbackContext;
} else if (ACTION_ADD_MOTION_CHANGE_LISTENER.equalsIgnoreCase(action)) {
result = true;
this.addMotionChangeListener(callbackContext);
} else if (ACTION_GET_LOCATIONS.equalsIgnoreCase(action)) {
result = true;
Bundle event = new Bundle();
......@@ -171,53 +186,25 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
resetOdometerCallback = callbackContext;
EventBus.getDefault().post(event);
} else if (ACTION_ADD_GEOFENCE.equalsIgnoreCase(action)) {
result = true;
JSONObject config = data.getJSONObject(0);
try {
Bundle event = new Bundle();
event.putString("name", action);
event.putBoolean("request", true);
event.putFloat("radius", (float) config.getLong("radius"));
event.putDouble("latitude", config.getDouble("latitude"));
event.putDouble("longitude", config.getDouble("longitude"));
event.putString("identifier", config.getString("identifier"));
if (config.has("notifyOnEntry")) {
event.putBoolean("notifyOnEntry", config.getBoolean("notifyOnEntry"));
}
if (config.has("notifyOnExit")) {
event.putBoolean("notifyOnExit", config.getBoolean("notifyOnExit"));
}
EventBus.getDefault().post(event);
result = onAddGeofence(data.getJSONObject(0));
if (result) {
callbackContext.success();
} catch (JSONException e) {
Log.w(TAG, e);
} else {
callbackContext.error("Failed to add geofence");
result = false;
}
} else if (ACTION_REMOVE_GEOFENCE.equalsIgnoreCase(action)) {
result = true;
try {
Bundle event = new Bundle();
event.putString("name", action);
event.putBoolean("request", true);
event.putString("identifier", data.getString(0));
EventBus.getDefault().post(event);
result = onRemoveGeofence(data.getString(0));
if (result) {
callbackContext.success();
} catch (JSONException e) {
Log.w(TAG, e);
} else {
callbackContext.error("Failed to add geofence");
result = false;
}
} else if (ACTION_ON_GEOFENCE.equalsIgnoreCase(action)) {
result = true;
geofenceCallbacks.add(callbackContext);
addGeofenceListener(callbackContext);
} else if (ACTION_GET_GEOFENCES.equalsIgnoreCase(action)) {
result = true;
getGeofencesCallback = callbackContext;
Bundle event = new Bundle();
event.putString("name", action);
event.putBoolean("request", true);
......@@ -226,15 +213,108 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
result = true;
playSound(data.getInt(0));
callbackContext.success();
} else if (BackgroundGeolocationService.ACTION_GET_CURRENT_POSITION.equalsIgnoreCase(action)) {
result = true;
if (!isEnabled) {
callbackContext.error(401); // aka HTTP UNAUTHORIZED
} else {
onGetCurrentPosition(callbackContext);
}
}
return result;
}
private void onGetCurrentPosition(CallbackContext callbackContext) {
isAcquiringCurrentPosition = true;
isAcquiringCurrentPositionSince = System.nanoTime();
addCurrentPositionListener(callbackContext);
Bundle event = new Bundle();
event.putString("name", BackgroundGeolocationService.ACTION_GET_CURRENT_POSITION);
event.putBoolean("request", true);
EventBus.getDefault().post(event);
}
private Boolean onAddGeofence(JSONObject config) {
try {
Bundle event = new Bundle();
event.putString("name", ACTION_ADD_GEOFENCE);
event.putBoolean("request", true);
event.putFloat("radius", (float) config.getLong("radius"));
event.putDouble("latitude", config.getDouble("latitude"));
event.putDouble("longitude", config.getDouble("longitude"));
event.putString("identifier", config.getString("identifier"));
if (config.has("notifyOnEntry")) {
event.putBoolean("notifyOnEntry", config.getBoolean("notifyOnEntry"));
}
if (config.has("notifyOnExit")) {
event.putBoolean("notifyOnExit", config.getBoolean("notifyOnExit"));
}
EventBus.getDefault().post(event);
return true;
} catch (JSONException e) {
Log.w(TAG, e);
return false;
}
}
private void addGeofenceListener(CallbackContext callbackContext) {
geofenceCallbacks.add(callbackContext);
Activity activity = this.cordova.getActivity();
Intent launchIntent = activity.getIntent();
if (launchIntent.hasExtra("forceReload") && launchIntent.hasExtra("geofencingEvent")) {
try {
JSONObject geofencingEvent = new JSONObject(launchIntent.getStringExtra("geofencingEvent"));
handleGeofencingEvent(geofencingEvent);
} catch (JSONException e) {
Log.w(TAG, e);
}
}
}
private void addCurrentPositionListener(CallbackContext callbackContext) {
currentPositionCallbacks.add(callbackContext);
}
private void addMotionChangeListener(CallbackContext callbackContext) {
motionChangeCallbacks.add(callbackContext);
Activity activity = this.cordova.getActivity();
Intent launchIntent = activity.getIntent();
if (launchIntent.hasExtra("forceReload")) {
if (launchIntent.getStringExtra("name").equalsIgnoreCase(ACTION_ON_MOTION_CHANGE)) {
Bundle event = launchIntent.getExtras();
this.onEventMainThread(event);
}
}
}
private Boolean onRemoveGeofence(String identifier) {
Bundle event = new Bundle();
event.putString("name", ACTION_REMOVE_GEOFENCE);
event.putBoolean("request", true);
event.putString("identifier", identifier);
EventBus.getDefault().post(event);
return true;
}
private void setEnabled(boolean value) {
// Don't set a state that we're already in.
if (value == isEnabled) {
return;
}
isEnabled = value;
Activity activity = this.cordova.getActivity();
Intent launchIntent = this.cordova.getActivity().getIntent();
if (launchIntent.hasExtra("forceReload") && launchIntent.hasExtra("location")) {
try {
JSONObject location = new JSONObject(launchIntent.getStringExtra("location"));
onLocationChange(location);
} catch (JSONException e) {
Log.w(TAG, e);
}
}
Activity activity = this.cordova.getActivity();
SharedPreferences settings = activity.getSharedPreferences("TSLocationManager", 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("enabled", isEnabled);
......@@ -262,7 +342,6 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("activityIsActive", true);
editor.putBoolean("isMoving", isMoving);
if (config.has("distanceFilter")) {
editor.putFloat("distanceFilter", config.getInt("distanceFilter"));
......@@ -282,6 +361,9 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
if (config.has("minimumActivityRecognitionConfidence")) {
editor.putInt("minimumActivityRecognitionConfidence", config.getInt("minimumActivityRecognitionConfidence"));
}
if (config.has("triggerActivities")) {
editor.putString("triggerActivities", config.getString("triggerActivities"));
}
if (config.has("stopTimeout")) {
editor.putLong("stopTimeout", config.getLong("stopTimeout"));
}
......@@ -298,8 +380,17 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
if (config.has("startOnBoot")) {
editor.putBoolean("startOnBoot", config.getBoolean("startOnBoot"));
}
if (config.has("forceReload")) {
editor.putBoolean("forceReload", config.getBoolean("forceReload"));
if (config.has("forceReloadOnLocationChange")) {
editor.putBoolean("forceReloadOnLocationChange", config.getBoolean("forceReloadOnLocationChange"));
}
if (config.has("forceReload")) { // @deprecated, alias to #forceReloadOnLocationChange
editor.putBoolean("forceReloadOnLocationChange", config.getBoolean("forceReload"));
}
if (config.has("forceReloadOnMotionChange")) {
editor.putBoolean("forceReloadOnMotionChange", config.getBoolean("forceReloadOnMotionChange"));
}
if (config.has("forceReloadOnGeofence")) {
editor.putBoolean("forceReloadOnGeofence", config.getBoolean("forceReloadOnGeofence"));
}
if (config.has("url")) {
editor.putString("url", config.getString("url"));
......@@ -391,9 +482,11 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
} else if (ACTION_RESET_ODOMETER.equalsIgnoreCase(name)) {
PluginResult result = new PluginResult(PluginResult.Status.OK);
resetOdometerCallback.sendPluginResult(result);
} else if (ACTION_ON_PACE_CHANGE.equalsIgnoreCase(name)) {
PluginResult result = new PluginResult(PluginResult.Status.OK);
paceChangeCallback.sendPluginResult(result);
} else if (BackgroundGeolocationService.ACTION_CHANGE_PACE.equalsIgnoreCase(name)) {
//PluginResult result = new PluginResult(PluginResult.Status.OK);
//paceChangeCallback.sendPluginResult(result);
int state = event.getBoolean("isMoving") ? 1 : 0;
paceChangeCallback.success(state);
} else if (ACTION_GET_GEOFENCES.equalsIgnoreCase(name)) {
try {
JSONArray json = new JSONArray(event.getString("data"));
......@@ -405,36 +498,72 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
PluginResult result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
runInBackground(getGeofencesCallback, result);
}
} else if (ACTION_ON_MOTION_CHANGE.equalsIgnoreCase(name)) {
this.onMotionChange(event);
}
}
private void onMotionChange(Bundle event) {
PluginResult result;
try {
JSONObject params = new JSONObject();
params.put("location", new JSONObject(event.getString("location")));
params.put("isMoving", event.getBoolean("isMoving"));
params.put("taskId", "android-bg-task-id");
result = new PluginResult(PluginResult.Status.OK, params);
} catch (JSONException e) {
e.printStackTrace();
result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
}
result.setKeepCallback(true);
for (CallbackContext callback : motionChangeCallbacks) {
runInBackground(callback, result);
}
}
/**
* EventBus listener for ARS
* @param {ActivityRecognitionResult} result
*/
public void onEventMainThread(ActivityRecognitionResult result) {
currentActivity = result.getMostProbableActivity();
String activityName = BackgroundGeolocationService.getActivityName(currentActivity.getType());
int confidence = currentActivity.getConfidence();
if (isAcquiringCurrentPosition) {
long elapsedMillis = (System.nanoTime() - isAcquiringCurrentPositionSince) / 1000000;
if (elapsedMillis > GET_CURRENT_POSITION_TIMEOUT) {
isAcquiringCurrentPosition = false;
Log.i(TAG, "- getCurrentPosition timeout, giving up");
for (CallbackContext callback : currentPositionCallbacks) {
callback.error(408); // aka HTTP 408 Request Timeout
}
currentPositionCallbacks.clear();
}
}
}
/**
* EventBus listener
* @param {Location} location
*/
public void onEventMainThread(Location location) {
PluginResult result;
result = new PluginResult(PluginResult.Status.OK, BackgroundGeolocationService.locationToJson(location, currentActivity));
JSONObject locationData = BackgroundGeolocationService.locationToJson(location, currentActivity);
this.onLocationChange(locationData);
}
private void onLocationChange(JSONObject location) {
PluginResult result = new PluginResult(PluginResult.Status.OK, location);
result.setKeepCallback(true);
if (location instanceof com.transistorsoft.locationmanager.BackgroundGeolocationService.StationaryLocation) {
isMoving = false;
if (stationaryCallback != null) {
runInBackground(stationaryCallback, result);
isMoving = true;
result.setKeepCallback(true);
runInBackground(locationCallback, result);
if (isAcquiringCurrentPosition) {
// Current position has arrived: release the hounds.
isAcquiringCurrentPosition = false;
for (CallbackContext callback : currentPositionCallbacks) {
result = new PluginResult(PluginResult.Status.OK, location);
result.setKeepCallback(false);
runInBackground(callback, result);
}
} else {
isMoving = true;
result.setKeepCallback(true);
runInBackground(locationCallback, result);
currentPositionCallbacks.clear();
}
}
/**
......@@ -445,30 +574,18 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
if (!geofenceCallbacks.isEmpty()) {
for (Geofence geofence : geofenceEvent.getTriggeringGeofences()) {
JSONObject params = new JSONObject();
String action = "";
int transitionType = geofenceEvent.getGeofenceTransition();
if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER) {
action = "ENTER";
} else if (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
action = "EXIT";
} else {
action = "DWELL";
}
try {
params.put("identifier", geofence.getRequestId());
params.put("action", action);
} catch (JSONException e) {
e.printStackTrace();
}
PluginResult result = new PluginResult(PluginResult.Status.OK, params);
result.setKeepCallback(true);
for (CallbackContext callback : geofenceCallbacks) {
runInBackground(callback, result);
}
JSONObject params = BackgroundGeolocationService.geofencingEventToJson(geofenceEvent, geofence);
handleGeofencingEvent(params);
}
}
}
private void handleGeofencingEvent(JSONObject params) {
PluginResult result = new PluginResult(PluginResult.Status.OK, params);
result.setKeepCallback(true);
for (CallbackContext callback : geofenceCallbacks) {
runInBackground(callback, result);
}
}
private void playSound(int soundId) {
int duration = 1000;
......
......@@ -12,17 +12,20 @@
@property (nonatomic, strong) NSString* syncCallbackId;
@property (nonatomic) UIBackgroundTaskIdentifier syncTaskId;
@property (nonatomic, strong) NSString* locationCallbackId;
@property (nonatomic, strong) NSMutableArray* currentPositionListeners;
@property (nonatomic, strong) NSMutableArray* geofenceListeners;
@property (nonatomic, strong) NSMutableArray* stationaryRegionListeners;
@property (nonatomic, strong) NSMutableArray* motionChangeListeners;
- (void) configure:(CDVInvokedUrlCommand*)command;
- (void) start:(CDVInvokedUrlCommand*)command;
- (void) stop:(CDVInvokedUrlCommand*)command;
- (void) finish:(CDVInvokedUrlCommand*)command;
- (void) error:(CDVInvokedUrlCommand*)command;
- (void) onPaceChange:(CDVInvokedUrlCommand*)command;
- (void) changePace:(CDVInvokedUrlCommand*)command;
- (void) setConfig:(CDVInvokedUrlCommand*)command;
- (void) addStationaryRegionListener:(CDVInvokedUrlCommand*)command;
- (void) addMotionChangeListener:(CDVInvokedUrlCommand*)command;
- (void) getStationaryLocation:(CDVInvokedUrlCommand *)command;
- (void) getLocations:(CDVInvokedUrlCommand *)command;
- (void) sync:(CDVInvokedUrlCommand *)command;
......@@ -32,6 +35,7 @@
- (void) removeGeofence:(CDVInvokedUrlCommand *)command;
- (void) getGeofences:(CDVInvokedUrlCommand *)command;
- (void) onGeofence:(CDVInvokedUrlCommand *)command;
- (void) getCurrentPosition:(CDVInvokedUrlCommand *)command;
- (void) playSound:(CDVInvokedUrlCommand *)command;
@end
......@@ -10,16 +10,17 @@
NSDictionary *config;
}
@synthesize syncCallbackId, syncTaskId, locationCallbackId, geofenceListeners, stationaryRegionListeners;
@synthesize syncCallbackId, syncTaskId, locationCallbackId, geofenceListeners, stationaryRegionListeners, motionChangeListeners, currentPositionListeners;
- (void)pluginInitialize
{
bgGeo = [[TSLocationManager alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onLocationChanged:) name:@"TSLocationManager.location" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onStationaryLocation:) name:@"TSLocationManager.stationary" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMotionChange:) name:@"TSLocationManager.motionchange" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onEnterGeofence:) name:@"TSLocationManager.geofence" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onSyncComplete:) name:@"TSLocationManager.sync" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onLocationManagerError:) name:@"TSLocationManager.error" object:nil];
}
/**
......@@ -54,6 +55,9 @@
- (void) start:(CDVInvokedUrlCommand*)command
{
[bgGeo start];
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool: true];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
/**
* Turn it off
......@@ -61,6 +65,8 @@
- (void) stop:(CDVInvokedUrlCommand*)command
{
[bgGeo stop];
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool: false];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
- (void) getOdometer:(CDVInvokedUrlCommand*)command
{
......@@ -78,10 +84,12 @@
* Change pace to moving/stopped
* @param {Boolean} isMoving
*/
- (void) onPaceChange:(CDVInvokedUrlCommand *)command
- (void) changePace:(CDVInvokedUrlCommand *)command
{
BOOL moving = [[command.arguments objectAtIndex: 0] boolValue];
[bgGeo onPaceChange:moving];
[bgGeo changePace:moving];
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool: moving];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
/**
......@@ -90,8 +98,9 @@
- (void)onLocationChanged:(NSNotification*)notification {
CLLocation *location = [notification.userInfo objectForKey:@"location"];
NSDictionary *locationData = [bgGeo locationToDictionary:location];
NSDictionary *params = @{
@"location": [bgGeo locationToDictionary:location],
@"location": locationData,
@"taskId": @([bgGeo createBackgroundTask])
};
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:params];
......@@ -100,18 +109,52 @@
[self.commandDelegate runInBackground:^{
[self.commandDelegate sendPluginResult:result callbackId:self.locationCallbackId];
}];
if ([self.currentPositionListeners count]) {
for (NSString *callbackId in self.currentPositionListeners) {
NSDictionary *params = @{
@"location": locationData,
@"taskId": @([bgGeo createBackgroundTask])
};
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:params];
[result setKeepCallbackAsBool:NO];
[self.commandDelegate runInBackground:^{
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}];
}
[self.currentPositionListeners removeAllObjects];
}
}
- (void) onStationaryLocation:(NSNotification*)notification
- (void) onMotionChange:(NSNotification*)notification
{
if (![self.stationaryRegionListeners count]) {
if (![self.stationaryRegionListeners count] && ![self.motionChangeListeners count]) {
return;
}
CLLocation *location = [notification.userInfo objectForKey:@"location"];
NSDictionary *locationData = [bgGeo locationToDictionary:location];
BOOL isMoving = [[notification.userInfo objectForKey:@"isMoving"] boolValue];
CLLocation *location = [notification.userInfo objectForKey:@"location"];
NSDictionary *locationData = [bgGeo locationToDictionary:location];
for (NSString *callbackId in self.stationaryRegionListeners) {
// @deprecated stationaryRegionListeners in favour of dual-function motionChangeListeners
if (!isMoving) {
for (NSString *callbackId in self.stationaryRegionListeners) {
NSLog(@"- CALLBACK: %@", callbackId);
NSDictionary *params = @{
@"isMoving": @(isMoving),
@"location": locationData,
@"taskId": @([bgGeo createBackgroundTask])
};
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:params];
[result setKeepCallbackAsBool:YES];
[self.commandDelegate runInBackground:^{
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}];
}
}
for (NSString *callbackId in self.motionChangeListeners) {
NSDictionary *params = @{
@"isMoving": @(isMoving),
@"location": locationData,
@"taskId": @([bgGeo createBackgroundTask])
};
......@@ -120,7 +163,6 @@
[self.commandDelegate runInBackground:^{
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}];
}
}
......@@ -149,6 +191,9 @@
- (void) onSyncComplete:(NSNotification*)notification
{
if (syncCallbackId == nil) {
return;
}
NSDictionary *params = @{
@"locations": [notification.userInfo objectForKey:@"locations"],
@"taskId": @(syncTaskId)
......@@ -217,6 +262,14 @@
[self.stationaryRegionListeners addObject:command.callbackId];
}
- (void) addMotionChangeListener:(CDVInvokedUrlCommand*)command
{
if (self.motionChangeListeners == nil) {
self.motionChangeListeners = [[NSMutableArray alloc] init];
}
[self.motionChangeListeners addObject:command.callbackId];
}
- (void) addGeofence:(CDVInvokedUrlCommand*)command
{
NSDictionary *cfg = [command.arguments objectAtIndex:0];
......@@ -261,7 +314,6 @@
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
- (void) onGeofence:(CDVInvokedUrlCommand*)command
{
if (self.geofenceListeners == nil) {
......@@ -270,6 +322,22 @@
[self.geofenceListeners addObject:command.callbackId];
}
- (void) getCurrentPosition:(CDVInvokedUrlCommand*)command
{
if (![bgGeo isEnabled]) {
NSLog(@"- CDVBackgroundGeolocation#getCurrentPosition cannot be used when plugin is disabled");
// If plugin isn't enabled, return 401 Unauthorized
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:401];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
return;
}
if (self.currentPositionListeners == nil) {
self.currentPositionListeners = [[NSMutableArray alloc] init];
}
[self.currentPositionListeners addObject:command.callbackId];
[bgGeo updateCurrentPosition];
}
- (void) playSound:(CDVInvokedUrlCommand*)command
{
int soundId = [[command.arguments objectAtIndex:0] integerValue];
......@@ -295,8 +363,26 @@
UIBackgroundTaskIdentifier taskId = [[command.arguments objectAtIndex: 0] integerValue];
NSString *error = [command.arguments objectAtIndex:1];
[bgGeo error:taskId message:error];
}
- (void) onLocationManagerError:(NSNotification*)notification
{
NSLog(@" - onLocationManagerError: %@", notification.userInfo);
NSString *errorType = [notification.userInfo objectForKey:@"type"];
if ([errorType isEqualToString:@"location"]) {
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:[[notification.userInfo objectForKey:@"code"] intValue]];
if ([self.currentPositionListeners count]) {
[result setKeepCallbackAsBool:NO];
for (NSString *callbackId in self.currentPositionListeners) {
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
}
[self.currentPositionListeners removeAllObjects];
}
[self.commandDelegate sendPluginResult:result callbackId:locationCallbackId];
}
}
/**
* If you don't stopMonitoring when application terminates, the app will be awoken still when a
* new location arrives, essentially monitoring the user's location even when they've killed the app.
......
......@@ -6,6 +6,7 @@
@property (nonatomic) CLLocationDistance odometer;
@property (nonatomic, strong) CLLocationManager* locationManager;
- (void) configure:(NSDictionary*)config;
- (void) start;
- (void) stop;
......@@ -14,7 +15,7 @@
- (UIBackgroundTaskIdentifier) createBackgroundTask;
- (void) stopBackgroundTask:(UIBackgroundTaskIdentifier)taskId;
- (void) error:(UIBackgroundTaskIdentifier)taskId message:(NSString*)message;
- (void) onPaceChange:(BOOL)value;
- (void) changePace:(BOOL)value;
- (void) setConfig:(NSDictionary*)command;
- (NSDictionary*) getStationaryLocation;
- (void) onSuspend:(NSNotification *)notification;
......@@ -25,6 +26,7 @@
- (void) addGeofence:(NSString*)identifier radius:(CLLocationDistance)radius latitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude notifyOnEntry:(BOOL)notifyOnEntry notifyOnExit:(BOOL)notifyOnExit;
- (BOOL) removeGeofence:(NSString*)identifier;
- (NSArray*) getGeofences;
- (void) updateCurrentPosition;
- (void) playSound:(SystemSoundID)soundId;
@end
......@@ -6,7 +6,7 @@
<dict>
<key>Headers/TSLocationManager.h</key>
<data>
++tA66F/FJQ/qMup0fGBER20r9U=
dTpEJTYyFANcuJNr9upQ8PrgD3Q=
</data>
<key>Info.plist</key>
<data>
......@@ -21,7 +21,7 @@
<dict>
<key>Headers/TSLocationManager.h</key>
<data>
++tA66F/FJQ/qMup0fGBER20r9U=
dTpEJTYyFANcuJNr9upQ8PrgD3Q=
</data>
<key>Modules/module.modulemap</key>
<data>
......
......@@ -83,7 +83,7 @@ module.exports = {
exec(success || function() {},
failure || function() {},
'BackgroundGeoLocation',
'onPaceChange',
'changePace',
[isMoving]);
},
/**
......@@ -112,6 +112,7 @@ module.exports = {
},
/**
* Add a stationary-region listener. Whenever the devices enters "stationary-mode", your #success callback will be executed with #location param containing #radius of region
* @deprecated in favour of dual-function #onMotionChange
* @param {Function} success
* @param {Function} failure [optional] NOT IMPLEMENTED
*/
......@@ -136,6 +137,35 @@ module.exports = {
'addStationaryRegionListener',
[]);
},
/**
* Add a movement-state-change listener. Whenever the devices enters "stationary" or "moving" mode, your #success callback will be executed with #location param containing #radius of region
* @param {Function} success
* @param {Function} failure [optional] NOT IMPLEMENTED
*/
onMotionChange: function(success, failure) {
var me = this;
success = success || function(isMoving, location, taskId) {
me.finish(taskId);
};
var callback = function(params) {
var isMoving = params.isMoving;
var location = params.location;
var taskId = params.taskId || 'task-id-undefined';
if (!isMoving) {
me.stationaryLocation = location;
}
me._runBackgroundTask(taskId, function() {
success.call(me, isMoving, location, taskId);
}, failure);
};
exec(callback,
failure || function() {},
'BackgroundGeoLocation',
'addMotionChangeListener',
[]);
},
getLocations: function(success, failure) {
if (typeof(success) !== 'function') {
throw "BackgroundGeolocation#getLocations requires a success callback";
......@@ -263,6 +293,31 @@ module.exports = {
[]);
},
/**
* Fetch the current position
*/
getCurrentPosition: function(success, failure) {
var me = this;
success = success || function(location, taskId) {
me.finish(taskId);
};
var mySuccess = function(params) {
var location = params.location || params;
var taskId = params.taskId || 'task-id-undefined';
// Transform timestamp to Date instance.
if (location.timestamp) {
location.timestamp = new Date(location.timestamp);
}
me._runBackgroundTask(taskId, function() {
success.call(this, location, taskId);
});
}
exec(mySuccess || function() {},
failure || function() {},
'BackgroundGeoLocation',
'getCurrentPosition',
[]);
},
/**
* Play a system sound. This is totally experimental.
* iOS http://iphonedevwiki.net/index.php/AudioServices
* Android:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment