Commit 797c1a78 authored by Mark Pearce's avatar Mark Pearce

Updated OBJ-C and Java to have new option parameter 'stopOnTerminate'

parent 5e1376a4
......@@ -5,16 +5,16 @@ Cross-platform background geolocation for Cordova / PhoneGap with battery-saving
Follows the [Cordova Plugin spec](https://github.com/apache/cordova-plugman/blob/master/plugin_spec.md), so that it works with [Plugman](https://github.com/apache/cordova-plugman).
This plugin leverages Cordova/PhoneGap's [require/define functionality used for plugins](http://simonmacdonald.blogspot.ca/2012/08/so-you-wanna-write-phonegap-200-android.html).
This plugin leverages Cordova/PhoneGap's [require/define functionality used for plugins](http://simonmacdonald.blogspot.ca/2012/08/so-you-wanna-write-phonegap-200-android.html).
## Using the plugin ##
The plugin creates the object `window.plugins.backgroundGeoLocation` with the methods
The plugin creates the object `window.plugins.backgroundGeoLocation` with the methods
`configure(success, fail, option)`,
`configure(success, fail, option)`,
`start(success, fail)`
`stop(success, fail)`.
`stop(success, fail)`.
## Installing the plugin ##
......@@ -66,10 +66,10 @@ A full example could be:
var failureFn = function(error) {
console.log('BackgroundGeoLocation error');
}
// BackgroundGeoLocation is highly configurable.
bgGeo.configure(callbackFn, failureFn, {
url: 'http://only.for.android.com/update_location.json', // <-- Android ONLY: your server url to send locations to
url: 'http://only.for.android.com/update_location.json', // <-- Android ONLY: your server url to send locations to
params: {
auth_token: 'user_secret_auth_token', // <-- Android ONLY: HTTP POST params sent to your server when persisting locations.
foo: 'bar' // <-- Android ONLY: HTTP POST params sent to your server when persisting locations.
......@@ -79,11 +79,12 @@ A full example could be:
},
desiredAccuracy: 10,
stationaryRadius: 20,
distanceFilter: 30,
distanceFilter: 30,
notificationTitle: 'Background tracking', // <-- android only, customize the title of the notification
notificationText: 'ENABLED', // <-- android only, customize the text of the notification
activityType: 'AutomotiveNavigation',
debug: true // <-- enable this hear sounds for background-geolocation life-cycle.
debug: true, // <-- enable this hear sounds for background-geolocation life-cycle.
stopOnTerminate: false // <-- enable this to clear background location settings when the app terminates
});
// Turn ON the background-geolocation system. The user will be tracked whenever they suspend the app.
......@@ -120,7 +121,7 @@ Android **WILL NOT** execute your configured ```callbackFn```. The plugin manag
### WP8
On WP8 the plugin does not support the Stationairy location and does not implement ```getStationaryLocation()``` and ```onPaceChange()```.
Keep in mind that it is **not** possible to use ```start()``` at the ```pause``` event of Cordova/PhoneGap. WP8 suspend your app immediately and ```start()``` will not be executed. So make sure you fire ```start()``` before the app is closed/minimized.
Keep in mind that it is **not** possible to use ```start()``` at the ```pause``` event of Cordova/PhoneGap. WP8 suspend your app immediately and ```start()``` will not be executed. So make sure you fire ```start()``` before the app is closed/minimized.
### Config
......@@ -181,6 +182,10 @@ Compare now background-geolocation in the scope of a city. In this image, the l
![distanceFilter at city scale](/distance-filter-city.png "distanceFilter at city scale")
#####`@param {Boolean} stopOnTerminate`
Enable this in order to force a stop() when the application terminated (e.g. on iOS, double-tap home button, swipe away the app)
### Android Config
#####`@param {String} url`
......@@ -198,8 +203,8 @@ Optional HTTP headers POSTed to your server when persisting locations
#####`@param {String} notificationText/Title`
On Android devices it is required to have a notification in the drawer because it's a "foreground service". This gives it high priority, decreasing probability of OS killing it. To customize the title and text of the notification, set these options.
#####`@param {Integer} locationTimeout
#####`@param {Integer} locationTimeout
The minimum time interval between location updates, in seconds. See [Android docs](http://developer.android.com/reference/android/location/LocationManager.html#requestLocationUpdates(long,%20float,%20android.location.Criteria,%20android.app.PendingIntent)) for more information.
......
......@@ -20,9 +20,9 @@ public class BackgroundGpsPlugin extends CordovaPlugin {
public static final String ACTION_SET_CONFIG = "setConfig";
private Intent updateServiceIntent;
private Boolean isEnabled = false;
private String url;
private String params;
private String headers;
......@@ -33,12 +33,13 @@ public class BackgroundGpsPlugin extends CordovaPlugin {
private String isDebugging = "false";
private String notificationTitle = "Background tracking";
private String notificationText = "ENABLED";
private String stopOnTerminate = "false";
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
Activity activity = this.cordova.getActivity();
Boolean result = false;
updateServiceIntent = new Intent(activity, LocationUpdateService.class);
if (ACTION_START.equalsIgnoreCase(action) && !isEnabled) {
result = true;
if (params == null || headers == null || url == null) {
......@@ -56,6 +57,7 @@ public class BackgroundGpsPlugin extends CordovaPlugin {
updateServiceIntent.putExtra("isDebugging", isDebugging);
updateServiceIntent.putExtra("notificationTitle", notificationTitle);
updateServiceIntent.putExtra("notificationText", notificationText);
updateServiceIntent.putExtra("stopOnTerminate", stopOnTerminate);
activity.startService(updateServiceIntent);
isEnabled = true;
......@@ -69,8 +71,8 @@ public class BackgroundGpsPlugin extends CordovaPlugin {
result = true;
try {
// Params.
// 0 1 2 3 4 5 6 7 8 8 9
//[params, headers, url, stationaryRadius, distanceFilter, locationTimeout, desiredAccuracy, debug, notificationTitle, notificationText, activityType]
// 0 1 2 3 4 5 6 7 8 8 9 10
//[params, headers, url, stationaryRadius, distanceFilter, locationTimeout, desiredAccuracy, debug, notificationTitle, notificationText, activityType, stopOnTerminate]
this.params = data.getString(0);
this.headers = data.getString(1);
this.url = data.getString(2);
......@@ -81,6 +83,7 @@ public class BackgroundGpsPlugin extends CordovaPlugin {
this.isDebugging = data.getString(7);
this.notificationTitle = data.getString(8);
this.notificationText = data.getString(9);
this.stopOnTerminate = data.getString(10);
} catch (JSONException e) {
callbackContext.error("authToken/url required as parameters: " + e.getMessage());
}
......@@ -92,4 +95,16 @@ public class BackgroundGpsPlugin extends CordovaPlugin {
return result;
}
/**
* Override method in CordovaPlugin.
* Checks to see if it should turn off
*/
public void onDestroy() {
Activity activity = this.cordova.getActivity();
if(isEnabled && stopOnTerminate.equalsIgnoreCase("true")) {
activity.stopService(updateServiceIntent);
}
}
}
......@@ -61,15 +61,15 @@ public class LocationUpdateService extends Service implements LocationListener {
private static final String SINGLE_LOCATION_UPDATE_ACTION = "com.tenforwardconsulting.cordova.bgloc.SINGLE_LOCATION_UPDATE_ACTION";
private static final String STATIONARY_LOCATION_MONITOR_ACTION = "com.tenforwardconsulting.cordova.bgloc.STATIONARY_LOCATION_MONITOR_ACTION";
private static final long STATIONARY_TIMEOUT = 5 * 1000 * 60; // 5 minutes.
private static final long STATIONARY_LOCATION_POLLING_INTERVAL_LAZY = 3 * 1000 * 60; // 3 minutes.
private static final long STATIONARY_LOCATION_POLLING_INTERVAL_LAZY = 3 * 1000 * 60; // 3 minutes.
private static final long STATIONARY_LOCATION_POLLING_INTERVAL_AGGRESSIVE = 1 * 1000 * 60; // 1 minute.
private static final Integer MAX_STATIONARY_ACQUISITION_ATTEMPTS = 5;
private static final Integer MAX_SPEED_ACQUISITION_ATTEMPTS = 3;
private PowerManager.WakeLock wakeLock;
private Location lastLocation;
private long lastUpdateTime = 0l;
private JSONObject params;
private JSONObject headers;
private String url = "http://192.168.2.15:3000/users/current_location.json";
......@@ -81,12 +81,12 @@ public class LocationUpdateService extends Service implements LocationListener {
private long stationaryLocationPollingInterval;
private PendingIntent stationaryRegionPI;
private PendingIntent singleUpdatePI;
private Boolean isMoving = false;
private Boolean isAcquiringStationaryLocation = false;
private Boolean isAcquiringSpeed = false;
private Integer locationAcquisitionAttempts = 0;
private Integer desiredAccuracy = 100;
private Integer distanceFilter = 30;
private Integer scaledDistanceFilter;
......@@ -94,11 +94,12 @@ public class LocationUpdateService extends Service implements LocationListener {
private Boolean isDebugging;
private String notificationTitle = "Background checking";
private String notificationText = "ENABLED";
private Boolean stopOnTerminate;
private ToneGenerator toneGenerator;
private Criteria criteria;
private LocationManager locationManager;
private AlarmManager alarmManager;
private ConnectivityManager connectivityManager;
......@@ -116,41 +117,41 @@ public class LocationUpdateService extends Service implements LocationListener {
public void onCreate() {
super.onCreate();
Log.i(TAG, "OnCreate");
locationManager = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
toneGenerator = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
notificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// Stop-detection PI
stationaryAlarmPI = PendingIntent.getBroadcast(this, 0, new Intent(STATIONARY_ALARM_ACTION), 0);
registerReceiver(stationaryAlarmReceiver, new IntentFilter(STATIONARY_ALARM_ACTION));
// Stationary region PI
stationaryRegionPI = PendingIntent.getBroadcast(this, 0, new Intent(STATIONARY_REGION_ACTION), PendingIntent.FLAG_CANCEL_CURRENT);
registerReceiver(stationaryRegionReceiver, new IntentFilter(STATIONARY_REGION_ACTION));
// Stationary location monitor PI
stationaryLocationPollingPI = PendingIntent.getBroadcast(this, 0, new Intent(STATIONARY_LOCATION_MONITOR_ACTION), 0);
registerReceiver(stationaryLocationMonitorReceiver, new IntentFilter(STATIONARY_LOCATION_MONITOR_ACTION));
// One-shot PI (TODO currently unused)
// One-shot PI (TODO currently unused)
singleUpdatePI = PendingIntent.getBroadcast(this, 0, new Intent(SINGLE_LOCATION_UPDATE_ACTION), PendingIntent.FLAG_CANCEL_CURRENT);
registerReceiver(singleUpdateReceiver, new IntentFilter(SINGLE_LOCATION_UPDATE_ACTION));
////
// DISABLED
// Listen to Cell-tower switches (NOTE does not operate while suspended)
//telephonyManager.listen(phoneStateListener, LISTEN_CELL_LOCATION);
//
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
wakeLock.acquire();
// Location criteria
criteria = new Criteria();
criteria.setAltitudeRequired(false);
......@@ -162,7 +163,7 @@ public class LocationUpdateService extends Service implements LocationListener {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Received start id " + startId + ": " + intent);
if (intent != null) {
if (intent != null) {
try {
params = new JSONObject(intent.getStringExtra("params"));
headers = new JSONObject(intent.getStringExtra("headers"));
......@@ -211,16 +212,16 @@ public class LocationUpdateService extends Service implements LocationListener {
Log.i(TAG, "- notificationText: " + notificationText);
this.setPace(false);
//We want this service to continue running until it is explicitly stopped
return START_REDELIVER_INTENT;
}
@TargetApi(16)
private Notification buildForegroundNotification(Notification.Builder builder) {
return builder.build();
}
@SuppressWarnings("deprecation")
@TargetApi(15)
private Notification buildForegroundNotificationCompat(Notification.Builder builder) {
......@@ -236,26 +237,26 @@ public class LocationUpdateService extends Service implements LocationListener {
}
return super.stopService(intent);
}
/**
*
*
* @param value set true to engage "aggressive", battery-consuming tracking, false for stationary-region tracking
*/
private void setPace(Boolean value) {
Log.i(TAG, "setPace: " + value);
Boolean wasMoving = isMoving;
isMoving = value;
isAcquiringStationaryLocation = false;
isAcquiringSpeed = false;
stationaryLocation = null;
locationManager.removeUpdates(this);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setHorizontalAccuracy(translateDesiredAccuracy(desiredAccuracy));
criteria.setPowerRequirement(Criteria.POWER_HIGH);
if (isMoving) {
// setPace can be called while moving, after distanceFilter has been recalculated. We don't want to re-acquire velocity in this case.
if (!wasMoving) {
......@@ -271,7 +272,7 @@ public class LocationUpdateService extends Service implements LocationListener {
// Turn on each provider aggressively for a short period of time
List<String> matchingProviders = locationManager.getAllProviders();
for (String provider: matchingProviders) {
if (provider != LocationManager.PASSIVE_PROVIDER) {
if (provider != LocationManager.PASSIVE_PROVIDER) {
locationManager.requestLocationUpdates(provider, 0, 0, this);
}
}
......@@ -317,7 +318,7 @@ public class LocationUpdateService extends Service implements LocationListener {
public Location getLastBestLocation() {
int minDistance = (int) stationaryRadius;
long minTime = System.currentTimeMillis() - (locationTimeout * 1000);
Log.i(TAG, "- fetching last best location " + minDistance + "," + minTime);
Location bestResult = null;
float bestAccuracy = Float.MAX_VALUE;
......@@ -347,12 +348,12 @@ public class LocationUpdateService extends Service implements LocationListener {
public void onLocationChanged(Location location) {
Log.d(TAG, "- onLocationChanged: " + location.getLatitude() + "," + location.getLongitude() + ", accuracy: " + location.getAccuracy() + ", isMoving: " + isMoving + ", speed: " + location.getSpeed());
if (!isMoving && !isAcquiringStationaryLocation && stationaryLocation==null) {
// Perhaps our GPS signal was interupted, re-acquire a stationaryLocation now.
setPace(false);
}
if (isDebugging) {
Toast.makeText(this, "mv:"+isMoving+",acy:"+location.getAccuracy()+",v:"+location.getSpeed()+",df:"+scaledDistanceFilter, Toast.LENGTH_LONG).show();
}
......@@ -420,7 +421,7 @@ public class LocationUpdateService extends Service implements LocationListener {
Log.d(TAG, "Network unavailable, waiting for now");
}
}
/**
* Plays debug sound
* @param name
......@@ -428,7 +429,7 @@ public class LocationUpdateService extends Service implements LocationListener {
private void startTone(String name) {
int tone = 0;
int duration = 1000;
if (name.equals("beep")) {
tone = ToneGenerator.TONE_PROP_BEEP;
} else if (name.equals("beep_beep_beep")) {
......@@ -444,7 +445,7 @@ public class LocationUpdateService extends Service implements LocationListener {
}
toneGenerator.startTone(tone, duration);
}
public void resetStationaryAlarm() {
alarmManager.cancel(stationaryAlarmPI);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + STATIONARY_TIMEOUT, stationaryAlarmPI); // Millisec * Second * Minute
......@@ -462,7 +463,7 @@ public class LocationUpdateService extends Service implements LocationListener {
private void startMonitoringStationaryRegion(Location location) {
locationManager.removeUpdates(this);
stationaryLocation = location;
Log.i(TAG, "- startMonitoringStationaryRegion (" + location.getLatitude() + "," + location.getLongitude() + "), accuracy:" + location.getAccuracy());
// Here be the execution of the stationary region monitor
......@@ -473,10 +474,10 @@ public class LocationUpdateService extends Service implements LocationListener {
(long)-1,
stationaryRegionPI
);
startPollingStationaryLocation(STATIONARY_LOCATION_POLLING_INTERVAL_LAZY);
}
public void startPollingStationaryLocation(long interval) {
// proximity-alerts don't seem to work while suspended in latest Android 4.42 (works in 4.03). Have to use AlarmManager to sample
// location at regular intervals with a one-shot.
......@@ -485,7 +486,7 @@ public class LocationUpdateService extends Service implements LocationListener {
long start = System.currentTimeMillis() + (60 * 1000);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, start, interval, stationaryLocationPollingPI);
}
public void onPollStationaryLocation(Location location) {
if (isMoving) {
return;
......@@ -494,11 +495,11 @@ public class LocationUpdateService extends Service implements LocationListener {
startTone("beep");
}
float distance = abs(location.distanceTo(stationaryLocation) - stationaryLocation.getAccuracy() - location.getAccuracy());
if (isDebugging) {
Toast.makeText(this, "Stationary exit in " + (stationaryRadius-distance) + "m", Toast.LENGTH_LONG).show();
}
// TODO http://www.cse.buffalo.edu/~demirbas/publications/proximity.pdf
// determine if we're almost out of stationary-distance and increase monitoring-rate.
Log.i(TAG, "- distance from stationary location: " + distance);
......@@ -520,14 +521,14 @@ public class LocationUpdateService extends Service implements LocationListener {
}
// Cancel the periodic stationary location monitor alarm.
alarmManager.cancel(stationaryLocationPollingPI);
// Kill the current region-monitor we just walked out of.
locationManager.removeProximityAlert(stationaryRegionPI);
// Engage aggressive tracking.
this.setPace(true);
}
/**
* TODO Experimental cell-tower change system; something like ios significant changes.
*/
......@@ -559,7 +560,7 @@ public class LocationUpdateService extends Service implements LocationListener {
}
}
};
/**
* Broadcast receiver which detcts a user has stopped for a long enough time to be determined as STOPPED
*/
......@@ -670,9 +671,9 @@ public class LocationUpdateService extends Service implements LocationListener {
location.put("altitude", l.getAltitude());
location.put("recorded_at", dao.dateToString(l.getRecordedAt()));
params.put("location", location);
Log.i(TAG, "location: " + location.toString());
StringEntity se = new StringEntity(params.toString());
request.setEntity(se);
request.setHeader("Accept", "application/json");
......@@ -733,12 +734,12 @@ public class LocationUpdateService extends Service implements LocationListener {
alarmManager.cancel(stationaryAlarmPI);
alarmManager.cancel(stationaryLocationPollingPI);
toneGenerator.release();
unregisterReceiver(stationaryAlarmReceiver);
unregisterReceiver(singleUpdateReceiver);
unregisterReceiver(stationaryRegionReceiver);
unregisterReceiver(stationaryLocationMonitorReceiver);
if (stationaryLocation != null && !isMoving) {
try {
locationManager.removeProximityAlert(stationaryRegionPI);
......
......@@ -23,6 +23,7 @@
- (void) getStationaryLocation:(CDVInvokedUrlCommand *)command;
- (void) onSuspend:(NSNotification *)notification;
- (void) onResume:(NSNotification *)notification;
- (void) onAppTerminiate:(NSNotification*)notification;
@end
......@@ -21,36 +21,37 @@
BOOL isDebugging;
BOOL enabled;
BOOL isUpdatingLocation;
BOOL stopOnTerminate;
NSString *token;
NSString *url;
UIBackgroundTaskIdentifier bgTask;
NSDate *lastBgTaskAt;
NSError *locationError;
BOOL isMoving;
NSNumber *maxBackgroundHours;
CLLocationManager *locationManager;
UILocalNotification *localNotification;
CDVLocationData *locationData;
CLLocation *lastLocation;
NSMutableArray *locationQueue;
NSDate *suspendedAt;
CLLocation *stationaryLocation;
CLCircularRegion *stationaryRegion;
NSInteger locationAcquisitionAttempts;
BOOL isAcquiringStationaryLocation;
NSInteger maxStationaryLocationAttempts;
BOOL isAcquiringSpeed;
NSInteger maxSpeedAcquistionAttempts;
NSInteger stationaryRadius;
NSInteger distanceFilter;
NSInteger locationTimeout;
......@@ -66,10 +67,10 @@
// background location cache, for when no network is detected.
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
localNotification = [[UILocalNotification alloc] init];
localNotification.timeZone = [NSTimeZone defaultTimeZone];
locationQueue = [[NSMutableArray alloc] init];
isMoving = NO;
......@@ -77,14 +78,15 @@
stationaryLocation = nil;
stationaryRegion = nil;
isDebugging = NO;
stopOnTerminate = NO;
maxStationaryLocationAttempts = 4;
maxSpeedAcquistionAttempts = 3;
bgTask = UIBackgroundTaskInvalid;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onSuspend:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume:) name:UIApplicationWillEnterForegroundNotification object:nil];
}
/**
......@@ -101,7 +103,7 @@
// Params.
// 0 1 2 3 4 5 6 7 8 8 9
//[params, headers, url, stationaryRadius, distanceFilter, locationTimeout, desiredAccuracy, debug, notificationTitle, notificationText, activityType]
// UNUSED ANDROID VARS
//params = [command.arguments objectAtIndex: 0];
//headers = [command.arguments objectAtIndex: 1];
......@@ -112,14 +114,15 @@
desiredAccuracy = [self decodeDesiredAccuracy:[[command.arguments objectAtIndex: 6] intValue]];
isDebugging = [[command.arguments objectAtIndex: 7] boolValue];
activityType = [self decodeActivityType:[command.arguments objectAtIndex:9]];
stopOnTerminate = [[command.arguments objectAtIndex: 10] boolValue];
self.syncCallbackId = command.callbackId;
locationManager.activityType = activityType;
locationManager.pausesLocationUpdatesAutomatically = YES;
locationManager.distanceFilter = distanceFilter; // meters
locationManager.desiredAccuracy = desiredAccuracy;
NSLog(@"CDVBackgroundGeoLocation configure");
NSLog(@" - token: %@", token);
NSLog(@" - url: %@", url);
......@@ -129,6 +132,7 @@
NSLog(@" - desiredAccuracy: %ld", (long)desiredAccuracy);
NSLog(@" - activityType: %@", [command.arguments objectAtIndex:7]);
NSLog(@" - debug: %d", isDebugging);
NSLog(@" - stopOnTerminate: %d", stopOnTerminate);
}
- (void) addStationaryRegionListener:(CDVInvokedUrlCommand*)command
......@@ -158,7 +162,7 @@
if ([locationQueue count] > 0) {
NSMutableDictionary *data = [locationQueue lastObject];
[locationQueue removeObject:data];
// Create a background-task and delegate to Javascript for syncing location
bgTask = [self createBackgroundTask];
[self.commandDelegate runInBackground:^{
......@@ -170,7 +174,7 @@
{
NSLog(@"- CDVBackgroundGeoLocation setConfig");
NSDictionary *config = [command.arguments objectAtIndex:0];
if (config[@"desiredAccuracy"]) {
desiredAccuracy = [self decodeDesiredAccuracy:[config[@"desiredAccuracy"] floatValue]];
NSLog(@" desiredAccuracy: %@", config[@"desiredAccuracy"]);
......@@ -187,7 +191,7 @@
locationTimeout = [config[@"locationTimeout"] intValue];
NSLog(@" locationTimeout: %@", config[@"locationTimeout"]);
}
CDVPluginResult* result = nil;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
......@@ -234,9 +238,9 @@
{
enabled = YES;
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
NSLog(@"- CDVBackgroundGeoLocation start (background? %d)", state);
[locationManager startMonitoringSignificantLocationChanges];
if (state == UIApplicationStateBackground) {
[self setPace:isMoving];
......@@ -253,7 +257,7 @@
NSLog(@"- CDVBackgroundGeoLocation stop");
enabled = NO;
isMoving = NO;
[self stopUpdatingLocation];
[locationManager stopMonitoringSignificantLocationChanges];
if (stationaryRegion != nil) {
......@@ -263,7 +267,7 @@
CDVPluginResult* result = nil;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
/**
......@@ -291,7 +295,7 @@
isAcquiringSpeed = NO;
locationAcquisitionAttempts = 0;
stationaryLocation = nil;
if (isDebugging) {
AudioServicesPlaySystemSound (isMoving ? paceChangeYesSound : paceChangeNoSound);
}
......@@ -319,13 +323,13 @@
- (void) getStationaryLocation:(CDVInvokedUrlCommand *)command
{
NSLog(@"- CDVBackgroundGeoLocation getStationaryLocation");
// Build a resultset for javascript callback.
CDVPluginResult* result = nil;
if (stationaryLocation) {
NSMutableDictionary *returnInfo = [self locationToHash:stationaryLocation];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo];
} else {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:NO];
......@@ -337,7 +341,7 @@
{
NSMutableDictionary *returnInfo;
returnInfo = [NSMutableDictionary dictionaryWithCapacity:10];
NSNumber* timestamp = [NSNumber numberWithDouble:([location.timestamp timeIntervalSince1970] * 1000)];
[returnInfo setObject:timestamp forKey:@"timestamp"];
[returnInfo setObject:[NSNumber numberWithDouble:location.speed] forKey:@"speed"];
......@@ -347,7 +351,7 @@
[returnInfo setObject:[NSNumber numberWithDouble:location.altitude] forKey:@"altitude"];
[returnInfo setObject:[NSNumber numberWithDouble:location.coordinate.latitude] forKey:@"latitude"];
[returnInfo setObject:[NSNumber numberWithDouble:location.coordinate.longitude] forKey:@"longitude"];
return returnInfo;
}
/**
......@@ -366,7 +370,7 @@
{
NSLog(@"- CDVBackgroundGeoLocation suspend (enabled? %d)", enabled);
suspendedAt = [NSDate date];
if (enabled) {
// Sample incoming stationary-location candidate: Is it within the current stationary-region? If not, I guess we're moving.
if (!isMoving && stationaryRegion) {
......@@ -393,31 +397,45 @@
}
}
/**@
* Termination. Checks to see if it should turn off
*/
-(void) onAppTerminiate:(NSNotification *) notification
{
NSLog(@"- CDVBackgroundGeoLocation terminate");
if (isUpdatingLocation && stopOnTerminate) {
[self stopUpdatingLocation];
}
}
-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(@"- CDVBackgroundGeoLocation didUpdateLocations (isMoving: %d)", isMoving);
locationError = nil;
if (isMoving && !isUpdatingLocation) {
[self startUpdatingLocation];
}
CLLocation *location = [locations lastObject];
if (!isMoving && !isAcquiringStationaryLocation && !stationaryLocation) {
// Perhaps our GPS signal was interupted, re-acquire a stationaryLocation now.
[self setPace: NO];
}
// test the age of the location measurement to determine if the measurement is cached
// in most cases you will not want to rely on cached measurements
if ([self locationAge:location] > 5.0) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (location.horizontalAccuracy < 0) return;
lastLocation = location;
// test the measurement to see if it is more accurate than the previous measurement
if (isAcquiringStationaryLocation) {
NSLog(@"- Acquiring stationary location, accuracy: %f", location.horizontalAccuracy);
......@@ -508,7 +526,7 @@
[[data objectForKey:@"speed"] doubleValue],
(long) locationManager.distanceFilter,
[[data objectForKey:@"accuracy"] doubleValue]]];
AudioServicesPlaySystemSound (locationSyncSound);
}
......@@ -536,7 +554,7 @@
}
// Any javascript stationaryRegion event-listeners?
[data setObject:[NSNumber numberWithDouble:stationaryRadius] forKey:@"radius"];
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:data];
[result setKeepCallbackAsBool:YES];
for (NSString *callbackId in self.stationaryRegionListeners)
......@@ -550,13 +568,13 @@
*/
- (void) startMonitoringStationaryRegion:(CLLocation*)location {
stationaryLocation = location;
// fire onStationary @event for Javascript.
[self queue:location type:@"stationary"];
CLLocationCoordinate2D coord = [location coordinate];
NSLog(@"- CDVBackgroundGeoLocation createStationaryRegion (%f,%f)", coord.latitude, coord.longitude);
if (isDebugging) {
AudioServicesPlaySystemSound (acquiredLocationSound);
[self notify:[NSString stringWithFormat:@"Acquired stationary location\n%f, %f", location.coordinate.latitude,location.coordinate.longitude]];
......@@ -568,7 +586,7 @@
stationaryRegion = [[CLCircularRegion alloc] initWithCenter: coord radius:stationaryRadius identifier:@"BackgroundGeoLocation stationary region"];
stationaryRegion.notifyOnExit = YES;
[locationManager startMonitoringForRegion:stationaryRegion];
[self stopUpdatingLocation];
locationManager.distanceFilter = distanceFilter;
locationManager.desiredAccuracy = desiredAccuracy;
......@@ -644,7 +662,7 @@
AudioServicesPlaySystemSound (locationErrorSound);
[self notify:[NSString stringWithFormat:@"Location error: %@", error.localizedDescription]];
}
locationError = error;
switch(error.code) {
......
......@@ -22,12 +22,13 @@ module.exports = {
notificationTitle = config.notificationTitle || "Background tracking",
notificationText = config.notificationText || "ENABLED";
activityType = config.activityType || "OTHER";
stopOnTerminate = config.stopOnTerminate || false;
exec(success || function() {},
failure || function() {},
'BackgroundGeoLocation',
'configure',
[params, headers, url, stationaryRadius, distanceFilter, locationTimeout, desiredAccuracy, debug, notificationTitle, notificationText, activityType]
[params, headers, url, stationaryRadius, distanceFilter, locationTimeout, desiredAccuracy, debug, notificationTitle, notificationText, activityType, stopOnTerminate]
);
},
start: function(success, failure, config) {
......@@ -49,14 +50,14 @@ module.exports = {
failure || function() {},
'BackgroundGeoLocation',
'finish',
[]);
[]);
},
changePace: function(isMoving, success, failure) {
exec(success || function() {},
failure || function() {},
'BackgroundGeoLocation',
'onPaceChange',
[isMoving]);
[isMoving]);
},
/**
* @param {Integer} stationaryRadius
......@@ -75,7 +76,7 @@ module.exports = {
/**
* Returns current stationaryLocation if available. null if not
*/
getStationaryLocation: function(success, failure) {
getStationaryLocation: function(success, failure) {
exec(success || function() {},
failure || function() {},
'BackgroundGeoLocation',
......@@ -98,7 +99,7 @@ module.exports = {
failure || function() {},
'BackgroundGeoLocation',
'addStationaryRegionListener',
[]);
[]);
},
apply: function(destination, source) {
source = source || {};
......
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