Commit f6a27869 authored by Chris Scott's avatar Chris Scott

Merge branch 'colibri-software-master'

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