Commit 11c599de authored by Chris Scott's avatar Chris Scott

Merge pull request #47 from christocracy/odometer

Odometer
parents 0b91a967 8a07a3d6
BackgroundGeoLocation Background Geolocation
============================== ==============================
Cross-platform background geolocation for Cordova with battery-saving "circular region monitoring" and "stop detection". Cross-platform background geolocation for Cordova with battery-saving "circular region monitoring" and "stop detection".
...@@ -26,6 +26,10 @@ The plugin creates the object `window.plugins.backgroundGeoLocation` with the me ...@@ -26,6 +26,10 @@ The plugin creates the object `window.plugins.backgroundGeoLocation` with the me
`sync(callback, fail)` `sync(callback, fail)`
`getOdometer(callback, fail)`
`resetOdometer(callback, fail)`
## Installing the plugin ## ## Installing the plugin ##
``` ```
...@@ -157,9 +161,13 @@ $ cordova build ios ...@@ -157,9 +161,13 @@ $ cordova build ios
## Behaviour ## Behaviour
The plugin has features allowing you to control the behaviour of background-tracking, striking a balance between accuracy and battery-usage. In stationary-mode, the plugin attempts to descrease its power usage and accuracy by setting up a circular stationary-region of configurable #stationaryRadius. iOS has a nice system [Significant Changes API](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/occ/instm/CLLocationManager/startMonitoringSignificantLocationChanges), which allows the os to suspend your app until a cell-tower change is detected (typically 2-3 city-block change) Android uses the Google Play Services APIs [FusedLocationProvider API](https://developer.android.com/reference/com/google/android/gms/location/FusedLocationProviderApi.html) as well as the [ActivityRecognition API](https://developer.android.com/reference/com/google/android/gms/location/ActivityRecognitionApi.html) (for movement/stationary detection). Windows Phone does not have such a API. The plugin has features allowing you to control the behaviour of background-tracking, striking a balance between accuracy and battery-usage. In stationary-mode, the plugin attempts to descrease its power usage and accuracy by setting up a circular stationary-region of configurable #stationaryRadius.
iOS has a nice system [Significant Changes API](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/occ/instm/CLLocationManager/startMonitoringSignificantLocationChanges), which allows the os to suspend your app until a cell-tower change is detected (typically 2-3 city-block change)
The plugin will execute your configured ```callback``` provided to the ```#configure(callback, config)``` method. You must manually POST the received ```GeoLocation``` to your server using standard XHR, as well as manually cache a recieved location into ```localStorage``` if no network connection is available. Android uses the Google Play Services APIs [FusedLocationProvider API](https://developer.android.com/reference/com/google/android/gms/location/FusedLocationProviderApi.html) as well as the [ActivityRecognition API](https://developer.android.com/reference/com/google/android/gms/location/ActivityRecognitionApi.html) (for movement/stationary detection). Windows Phone does not have such a API.
The plugin will execute your configured ```callback``` provided to the ```#configure(callback, config)``` method. Both iOS & Android use a SQLite database to persist **every** recorded geolocation so you don't have to worry about persistence when no network is detected. The plugin provides a Javascript API to fetch and destroy the records in the database. In addition, the plugin has an optional HTTP layer allowing allowing you to automatically HTTP POST recorded geolocations to your server.
The function ```changePace(isMoving, success, failure)``` is provided to force the plugin to enter "moving" or "stationary" state. The function ```changePace(isMoving, success, failure)``` is provided to force the plugin to enter "moving" or "stationary" state.
...@@ -253,6 +261,20 @@ If the plugin is configured for HTTP with an ```#url``` and ```#autoSync: false` ...@@ -253,6 +261,20 @@ If the plugin is configured for HTTP with an ```#url``` and ```#autoSync: false`
``` ```
#####`getOdometer(callbackFn, failureFn)`
The plugin constantly tracks distance travelled. To fetch the current **odometer** reading:
```
bgGeo.getOdometer(function(distance) {
console.log("Distance travelled: ", distance);
});
```
#####`resetOdometer(callbackFn, failureFn)`
Reset the **odometer** to zero. The plugin never automatically resets the odometer so it's up to you to reset it as desired.
## Config ## Config
Use the following config-parameters with the #configure method: Use the following config-parameters with the #configure method:
...@@ -321,11 +343,24 @@ Enable this in order to force a stop() when the application terminated (e.g. on ...@@ -321,11 +343,24 @@ Enable this in order to force a stop() when the application terminated (e.g. on
The plugin can optionally auto-stop monitoring location when some number of minutes elapse after being the #start method was called. The plugin can optionally auto-stop monitoring location when some number of minutes elapse after being the #start method was called.
#### In-Plugin SQLite Storage
The plugin will cache **every** recorded geolocation to its internal SQLite database -- when you sync the locations and your server responds with HTTP ```200, 201 or 204```, the plugin will **DELETE** the stored location from cache. The plugin has a cache-pruning feature with ```@config {Integer} maxDaysToPersist``` -- If the plugin hasn't successfully synced these these records in the database before ```maxDaysToPersist``` expires, the plugin will give up and those geolocation records will be pruned from the database.
If you **don't** configure the optional HTTP feature, the only way to delete the SQLite database is by executing the ```#sync``` method.
```
bgGeo.sync(function(locations) {
// The SQLite database is now EMPTY.
console.log('locations: ', locations);
});
```
#### HTTP Features #### HTTP Features
#####`@param {String} url` #####`@param {String} url`
By configuring an ```#url```, the plugin will always attempt to HTTP POST the location to your server. Your server url where you wish to HTTP POST location data to.
#####`@param {String} batchSync [false]` #####`@param {String} batchSync [false]`
...@@ -333,7 +368,7 @@ Default is ```false```. If you've enabled HTTP feature by configuring an ```#ur ...@@ -333,7 +368,7 @@ Default is ```false```. If you've enabled HTTP feature by configuring an ```#ur
#####`@param {String} autoSync [true]` #####`@param {String} autoSync [true]`
Default is ```true```. If you've enabeld HTTP feature by configuring an ```#url```, the plugin will attempt to HTTP POST each location to your server as it is recorded. If you set ```autoSync: false```, it's up to you to manually execute the ```#sync``` method to initate the HTTP POST (**NOTE** The plugin will continue to persist **every** recorded location in the SQLite database until you execute ```#sync```). Default is ```true```. If you've enabeld HTTP feature by configuring an ```#url```, the plugin will attempt to HTTP POST each location to your server **as it is recorded**. If you set ```autoSync: false```, it's up to you to **manually** execute the ```#sync``` method to initate the HTTP POST (**NOTE** The plugin will continue to persist **every** recorded location in the SQLite database until you execute ```#sync```).
#####`@param {Object} params` #####`@param {Object} params`
...@@ -349,16 +384,14 @@ Maximum number of days to store a geolocation in plugin's SQLite database when y ...@@ -349,16 +384,14 @@ Maximum number of days to store a geolocation in plugin's SQLite database when y
Both iOS and Android can send the Geolocation to your server simply by configuring an ```#url``` in addition to optional ```#headers``` and ```#params```. This is the preferred way to send the Geolocation to your server, rather than doing it yourself with Ajax in your javascript. Both iOS and Android can send the Geolocation to your server simply by configuring an ```#url``` in addition to optional ```#headers``` and ```#params```. This is the preferred way to send the Geolocation to your server, rather than doing it yourself with Ajax in your javascript.
##### In-Plugin SQLite Storage
When you enable HTTP Feature by configuring an ```#url```, the plugin will cache every recorded geolocation to its internal SQLite database -- when your server responds with HTTP ```200, 201 or 204```, the plugin will DELETE the stored location from cache. The plugin has a cache-pruning feature with ```@config {Integer} maxDaysToPersist``` -- If your server hasn't responded with 200 before ```maxDaysToPersist``` expires, the plugin will give up on it and that geolocation will be pruned from the database.
``` ```
bgGeo.configure(callbackFn, failureFn, { bgGeo.configure(callbackFn, failureFn, {
. .
. .
. .
url: 'http://posttestserver.com/post.php?dir=cordova-background-geolocation', url: 'http://posttestserver.com/post.php?dir=cordova-background-geolocation',
autoSync: true,
batchSync: false,
maxDaysToPersist: 1, maxDaysToPersist: 1,
headers: { headers: {
"X-FOO": "bar" "X-FOO": "bar"
......
...@@ -35,6 +35,8 @@ public class CDVBackgroundGeolocation extends CordovaPlugin { ...@@ -35,6 +35,8 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
public static final String ACTION_ON_STATIONARY = "addStationaryRegionListener"; public static final String ACTION_ON_STATIONARY = "addStationaryRegionListener";
public static final String ACTION_GET_LOCATIONS = "getLocations"; public static final String ACTION_GET_LOCATIONS = "getLocations";
public static final String ACTION_SYNC = "sync"; public static final String ACTION_SYNC = "sync";
public static final String ACTION_GET_ODOMETER = "getOdometer";
public static final String ACTION_RESET_ODOMETER = "resetOdometer";
private Boolean isEnabled = false; private Boolean isEnabled = false;
private Boolean stopOnTerminate = false; private Boolean stopOnTerminate = false;
...@@ -53,6 +55,10 @@ public class CDVBackgroundGeolocation extends CordovaPlugin { ...@@ -53,6 +55,10 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
private CallbackContext syncCallback; private CallbackContext syncCallback;
private CallbackContext getOdometerCallback;
private CallbackContext resetOdometerCallback;
public static boolean isActive() { public static boolean isActive() {
return gWebView != null; return gWebView != null;
} }
...@@ -124,6 +130,20 @@ public class CDVBackgroundGeolocation extends CordovaPlugin { ...@@ -124,6 +130,20 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
event.putBoolean("request", true); event.putBoolean("request", true);
syncCallback = callbackContext; syncCallback = callbackContext;
EventBus.getDefault().post(event); EventBus.getDefault().post(event);
} else if (ACTION_GET_ODOMETER.equalsIgnoreCase(action)) {
result = true;
Bundle event = new Bundle();
event.putString("name", action);
event.putBoolean("request", true);
getOdometerCallback = callbackContext;
EventBus.getDefault().post(event);
} else if (ACTION_RESET_ODOMETER.equalsIgnoreCase(action)) {
result = true;
Bundle event = new Bundle();
event.putString("name", action);
event.putBoolean("request", true);
resetOdometerCallback = callbackContext;
EventBus.getDefault().post(event);
} }
return result; return result;
} }
...@@ -271,6 +291,12 @@ public class CDVBackgroundGeolocation extends CordovaPlugin { ...@@ -271,6 +291,12 @@ public class CDVBackgroundGeolocation extends CordovaPlugin {
PluginResult result = new PluginResult(PluginResult.Status.IO_EXCEPTION, event.getString("message")); PluginResult result = new PluginResult(PluginResult.Status.IO_EXCEPTION, event.getString("message"));
runInBackground(syncCallback, result); runInBackground(syncCallback, result);
} }
} else if (ACTION_GET_ODOMETER.equalsIgnoreCase(name)) {
PluginResult result = new PluginResult(PluginResult.Status.OK, event.getFloat("data"));
runInBackground(getOdometerCallback, result);
} else if (ACTION_RESET_ODOMETER.equalsIgnoreCase(name)) {
PluginResult result = new PluginResult(PluginResult.Status.OK);
runInBackground(resetOdometerCallback, result);
} }
} }
......
...@@ -22,5 +22,7 @@ ...@@ -22,5 +22,7 @@
- (void) getStationaryLocation:(CDVInvokedUrlCommand *)command; - (void) getStationaryLocation:(CDVInvokedUrlCommand *)command;
- (void) getLocations:(CDVInvokedUrlCommand *)command; - (void) getLocations:(CDVInvokedUrlCommand *)command;
- (void) sync:(CDVInvokedUrlCommand *)command; - (void) sync:(CDVInvokedUrlCommand *)command;
- (void) getOdometer:(CDVInvokedUrlCommand *)command;
- (void) resetOdometer:(CDVInvokedUrlCommand *)command;
@end @end
...@@ -60,6 +60,17 @@ ...@@ -60,6 +60,17 @@
{ {
[bgGeo stop]; [bgGeo stop];
} }
- (void) getOdometer:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble: bgGeo.odometer];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
- (void) resetOdometer:(CDVInvokedUrlCommand*)command
{
bgGeo.odometer = 0;
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
/** /**
* Change pace to moving/stopped * Change pace to moving/stopped
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
@interface TSLocationManager : NSObject <CLLocationManagerDelegate> @interface TSLocationManager : NSObject <CLLocationManagerDelegate>
@property (nonatomic) CLLocationDistance odometer;
- (void) configure:(NSDictionary*)config; - (void) configure:(NSDictionary*)config;
- (void) start; - (void) start;
- (void) stop; - (void) stop;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<dict> <dict>
<key>Headers/TSLocationManager.h</key> <key>Headers/TSLocationManager.h</key>
<data> <data>
uXAE4LxGF9ekkpUCvnRgTZf4wvM= cDmPMOfd6jEG9Kg62Au0tnkrqWA=
</data> </data>
<key>Info.plist</key> <key>Info.plist</key>
<data> <data>
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
<dict> <dict>
<key>Headers/TSLocationManager.h</key> <key>Headers/TSLocationManager.h</key>
<data> <data>
uXAE4LxGF9ekkpUCvnRgTZf4wvM= cDmPMOfd6jEG9Kg62Au0tnkrqWA=
</data> </data>
<key>Modules/module.modulemap</key> <key>Modules/module.modulemap</key>
<data> <data>
......
...@@ -136,7 +136,26 @@ module.exports = { ...@@ -136,7 +136,26 @@ module.exports = {
'sync', 'sync',
[]); []);
}, },
/**
* Fetch current odometer value
*/
getOdometer: function(success, failure) {
exec(success || function() {},
failure || function() {},
'BackgroundGeoLocation',
'getOdometer',
[]);
},
/**
* Reset Odometer to 0
*/
resetOdometer: function(success, failure) {
exec(success || function() {},
failure || function() {},
'BackgroundGeoLocation',
'resetOdometer',
[]);
},
_setTimestamp: function(rs) { _setTimestamp: function(rs) {
// Transform timestamp to Date instance. // Transform timestamp to Date instance.
if (typeof(rs) === 'object') { if (typeof(rs) === 'object') {
......
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