Commit 185020db authored by Chris Scott's avatar Chris Scott

Implement Android SharedPreferences for configuration. This allows much...

Implement Android SharedPreferences for configuration.  This allows much simpler configuration of auto-starting the device at device BOOT, since the BootReceiver can now read its configuration from SharedPreferences.  This also allows the plugin to always add the android permission BOOT_COMPLETED and teh state of @config startOnBoot will determine whether to start the service.  Better error-handling on params/headers config.  Tip-of-the-hat to Nicholas Felmlee for all this
parent 8ef8ff1d
......@@ -179,8 +179,9 @@ var app = {
locationUpdateInterval: 5000,
activityRecognitionInterval: 10000,
stopTimeout: 0,
forceReload: true, // <-- If the user closes the app **while location-tracking is started** , reboot app (WARNING: possibly distruptive to user)
stopOnTerminate: false, // <-- Allow the background-service to run headless when user closes the app.
forceReload: true, // <-- [Android] If the user closes the app **while location-tracking is started** , reboot app (WARNING: possibly distruptive to user)
stopOnTerminate: false, // <-- [Android] Allow the background-service to run headless when user closes the app.
startOnBoot: true, // <-- [Android] Auto start background-service in headless mode when device is powered-up.
activityType: 'AutomotiveNavigation'
/**
* HTTP Feature: set an url to allow the native background service to POST locations to your server
......
......@@ -58,9 +58,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<!-- Autorun your app on device BOOT. UNCOMMENT TO ENABLE AUTO-BOOT -->
<!-- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
</config-file>
<config-file target="res/xml/config.xml" parent="/*">
......
......@@ -15,6 +15,7 @@ import com.transistorsoft.cordova.bggeo.BackgroundGeolocationService.StationaryL
import de.greenrobot.event.EventBus;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.util.Log;
......@@ -93,11 +94,9 @@ public class BackgroundGeolocationPlugin extends CordovaPlugin {
callbackContext.success();
}
} else if (ACTION_SET_CONFIG.equalsIgnoreCase(action)) {
activity.stopService(backgroundServiceIntent);
result = applyConfig(data);
// TODO reconfigure Service
if (result) {
activity.startService(backgroundServiceIntent);
callbackContext.success();
} else {
callbackContext.error("- Configuration error!");
......@@ -110,47 +109,65 @@ public class BackgroundGeolocationPlugin extends CordovaPlugin {
}
private boolean applyConfig(JSONArray data) {
Activity activity = this.cordova.getActivity();
try {
JSONObject config = data.getJSONObject(0);
Log.i(TAG, "- configure: " + config.toString());
backgroundServiceIntent.putExtra("isMoving", isMoving);
SharedPreferences settings = activity.getSharedPreferences(TAG, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("isMoving", isMoving);
if (config.has("distanceFilter")) {
backgroundServiceIntent.putExtra("distanceFilter", (float) config.getInt("distanceFilter"));
editor.putFloat("distanceFilter", config.getInt("distanceFilter"));
}
if (config.has("desiredAccuracy")) {
backgroundServiceIntent.putExtra("desiredAccuracy", config.getInt("desiredAccuracy"));
editor.putInt("desiredAccuracy", config.getInt("desiredAccuracy"));
}
if (config.has("locationUpdateInterval")) {
backgroundServiceIntent.putExtra("locationUpdateInterval", config.getInt("locationUpdateInterval"));
editor.putInt("locationUpdateInterval", config.getInt("locationUpdateInterval"));
}
if (config.has("activityRecognitionInterval")) {
backgroundServiceIntent.putExtra("activityRecognitionInterval", config.getInt("activityRecognitionInterval"));
editor.putInt("activityRecognitionInterval", config.getInt("activityRecognitionInterval"));
}
if (config.has("stopTimeout")) {
backgroundServiceIntent.putExtra("stopTimeout", config.getLong("stopTimeout"));
editor.putLong("stopTimeout", config.getLong("stopTimeout"));
}
if (config.has("debug")) {
backgroundServiceIntent.putExtra("debug", config.getBoolean("debug"));
editor.putBoolean("debug", config.getBoolean("debug"));
}
if (config.has("stopOnTerminate")) {
stopOnTerminate = config.getBoolean("stopOnTerminate");
backgroundServiceIntent.putExtra("stopOnTerminate", config.getBoolean("stopOnTerminate"));
editor.putBoolean("stopOnTerminate", config.getBoolean("stopOnTerminate"));
}
if (config.has("startOnBoot")) {
editor.putBoolean("startOnBoot", config.getBoolean("startOnBoot"));
}
if (config.has("forceReload")) {
backgroundServiceIntent.putExtra("forceReload", config.getBoolean("forceReload"));
editor.putBoolean("forceReload", config.getBoolean("forceReload"));
}
if (config.has("url")) {
backgroundServiceIntent.putExtra("url", config.getString("url"));
editor.putString("url", config.getString("url"));
}
if (config.has("params")) {
backgroundServiceIntent.putExtra("params", config.getString("params"));
try {
editor.putString("params", config.getJSONObject("params").toString());
} catch (JSONException e) {
Log.w(TAG, "- Failed to parse #params to JSONObject. Ignored");
}
}
if (config.has("headers")) {
backgroundServiceIntent.putExtra("headers", config.getString("headers"));
try {
editor.putString("headers", config.getJSONObject("headers").toString());
} catch (JSONException e) {
Log.w(TAG, "- Failed to parse #headers to JSONObject. Ignored");
}
}
editor.commit();
return true;
} catch (JSONException e) {
Log.w(TAG, e);
return false;
}
}
......
......@@ -25,6 +25,7 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.media.AudioManager;
......@@ -58,19 +59,19 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
/**
* @config {Integer} desiredAccuracy
*/
private Integer desiredAccuracy = 10;
private Integer desiredAccuracy = 10;
/**
* @config {Float} distanceFilter
*/
private Float distanceFilter = (float) 50;
private Float distanceFilter = 50f;
/**
* @config {Boolean} isDebugging
*/
private Boolean isDebugging = false;
private Boolean isDebugging = false;
/**
* @config {Boolean} stopOnTerminate
*/
private Boolean stopOnTerminate = false;
private Boolean stopOnTerminate = false;
// Android-only config
/**
......@@ -92,21 +93,21 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
/**
* @config {Integer} stopTimeout The time to wait after ARS STILL to turn of GPS
*/
private long stopTimeout = 0;
private long stopTimeout = 0;
// HTTP config
/**
* @config {String} url For sending location to your server
*/
private String url = null;
private String url = null;
/**
* @config {JSONObject} params For sending location to your server
*/
private JSONObject params = new JSONObject();
private JSONObject params = new JSONObject();
/**
* @config {JSONObject} headers For sending location to your server
*/
private JSONObject headers = new JSONObject();
private JSONObject headers = new JSONObject();
// Flags
private Boolean isEnabled = false;
......@@ -123,31 +124,38 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
instance = this;
EventBus.getDefault().register(this);
// Load config settings
SharedPreferences settings = getSharedPreferences(TAG, 0);
isEnabled = true;
stopOnTerminate = intent.getBooleanExtra("stopOnTerminate", true);
isDebugging = intent.getBooleanExtra("debug", false);
distanceFilter = intent.getFloatExtra("distanceFilter", 50);
desiredAccuracy = intent.getIntExtra("desiredAccuracy", 10);
locationUpdateInterval = intent.getIntExtra("locationUpdateInterval", 30000);
activityRecognitionInterval = intent.getIntExtra("activityRecognitionInterval", 60000);
stopTimeout = intent.getLongExtra("stopTimeout", 0);
forceReload = intent.getBooleanExtra("forceReload", false);
isMoving = intent.getBooleanExtra("isMoving", false);
isDebugging = settings.getBoolean("debug", false);
distanceFilter = settings.getFloat("distanceFilter", 50);
desiredAccuracy = settings.getInt("desiredAccuracy", 10);
locationUpdateInterval = settings.getInt("locationUpdateInterval", 30000);
activityRecognitionInterval = settings.getInt("activityRecognitionInterval", 60000);
stopTimeout = settings.getLong("stopTimeout", 0);
stopOnTerminate = settings.getBoolean("stopOnTerminate", true);
forceReload = settings.getBoolean("forceReload", false);
isMoving = settings.getBoolean("isMoving", false);
// HTTP Configuration
url = intent.getStringExtra("url");
try {
if (intent.hasExtra("params")) {
params = new JSONObject(intent.getStringExtra("params"));
url = settings.getString("url", null);
if (settings.contains("params")) {
try {
params = new JSONObject(settings.getString("params", "{}"));
} catch (JSONException e) {
Log.w(TAG, "- Faile to parse #params to JSONObject");
}
if (intent.hasExtra("headers")) {
headers = new JSONObject(intent.getStringExtra("headers"));
}
if (settings.contains("headers")) {
try {
headers = new JSONObject(settings.getString("headers", "{}"));
} catch (JSONException e) {
Log.w(TAG, "- Failed to parse #headers to JSONObject");
}
} catch (JSONException e) {
e.printStackTrace();
}
Log.i(TAG, "----------------------------------------");
Log.i(TAG, "- Start BackgroundGeolocationService");
Log.i(TAG, " debug: " + isDebugging);
......@@ -159,6 +167,7 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
Log.i(TAG, " stopOnTerminate: " + stopOnTerminate);
Log.i(TAG, " forceReload: " + forceReload);
Log.i(TAG, " isMoving: " + isMoving);
Log.i(TAG, "----------------------------------------");
// For debug sounds, turn on ToneGenerator.
......@@ -182,7 +191,7 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
Log.e(TAG, "- GooglePlayServices unavailable");
}
return Service.START_REDELIVER_INTENT;
return Service.START_STICKY;
}
@Override
......@@ -370,7 +379,8 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
private Integer getLocationUpdateInterval() {
// TODO Can add intelligence here based upon currentActivity.
return locationUpdateInterval;
SharedPreferences settings = getSharedPreferences(TAG, 0);
return settings.getInt("locationUpdateInterval", locationUpdateInterval);
}
private Integer getFastestLocationUpdateInterval() {
......@@ -499,7 +509,8 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
}
private void requestActivityUpdates() {
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(googleApiClient, activityRecognitionInterval, activityRecognitionPI);
SharedPreferences settings = getSharedPreferences(TAG, 0);
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(googleApiClient, settings.getInt("activityRecognitionInterval", activityRecognitionInterval), activityRecognitionPI);
}
private void removeActivityUpdates() {
......@@ -509,12 +520,14 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
private void requestLocationUpdates() {
if (!isPaused || !isEnabled) { return; } // <-- Don't engage GPS when app is in foreground
SharedPreferences settings = getSharedPreferences(TAG, 0);
// Configure LocationRequest
locationRequest = LocationRequest.create()
.setPriority(translateDesiredAccuracy(desiredAccuracy))
.setPriority(translateDesiredAccuracy(settings.getInt("desiredAccuracy", desiredAccuracy)))
.setInterval(getLocationUpdateInterval())
.setFastestInterval(getFastestLocationUpdateInterval())
.setSmallestDisplacement(distanceFilter);
.setSmallestDisplacement(settings.getFloat("distanceFilter", distanceFilter));
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, locationUpdatePI);
}
......
......@@ -3,6 +3,7 @@ package com.transistorsoft.cordova.bggeo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
/**
* This boot receiver is meant to handle the case where device is first booted after power up.
......@@ -11,45 +12,18 @@ import android.util.Log;
*
*/
public class BootReceiver extends BroadcastReceiver {
private static final String TAG = "BackgroundGeolocation";
/**
* Background Geolocation Configuration params.
* If you're auto-running the service on BOOT, you need to manually configure the params here since the foreground app will not have been booted.
*/
private float distanceFilter = 50;
private Integer desiredAccuracy = 0;
private Integer locationUpdateInterval = 5000;
private Integer activityRecognitionInterval = 10000;
private long stopTimeout = 0;
private boolean debug = true;
private boolean stopOnTerminate = false;
private boolean forceReload = false;
private String url = "http://posttestserver.com/post.php?dir=cordova-background-geolocation";
private String params = "{'foo':'bar'}";
private String headers = "{'X-FOO':'BAR'}";
private static final String TAG = "BackgroundGeolocation";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "- BootReceiver booting service");
Intent backgroundServiceIntent = new Intent(context, BackgroundGeolocationService.class);
// Configure background geolocation service params.
backgroundServiceIntent.putExtra("distanceFilter", distanceFilter);
backgroundServiceIntent.putExtra("desiredAccuracy", desiredAccuracy);
backgroundServiceIntent.putExtra("locationUpdateInterval", locationUpdateInterval);
backgroundServiceIntent.putExtra("activityRecognitionInterval", activityRecognitionInterval);
backgroundServiceIntent.putExtra("stopTimeout", stopTimeout);
backgroundServiceIntent.putExtra("debug", debug);
backgroundServiceIntent.putExtra("stopOnTerminate", stopOnTerminate);
backgroundServiceIntent.putExtra("forceReload", forceReload);
backgroundServiceIntent.putExtra("url", url);
backgroundServiceIntent.putExtra("params", params);
backgroundServiceIntent.putExtra("headers", headers);
SharedPreferences settings = context.getSharedPreferences(TAG, 0);
boolean startOnBoot = settings.getBoolean("startOnBoot", false);
if (!startOnBoot) {
return;
}
Log.i(TAG, "- BootReceiver booting service");
// Start the service.
context.startService(backgroundServiceIntent);
context.startService(new Intent(context, BackgroundGeolocationService.class));
}
}
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