Commit d16f28c9 authored by Chris Scott's avatar Chris Scott

Implement BOOT_COMPLETED receiver. NOTE: You must manually add the android...

Implement BOOT_COMPLETED receiver.  NOTE:  You must manually add the android permission android.permission.RECEIVE_BOOT_COMPLETED to your AndroidManifest -- the plugin has this element in its plugin.xml purposely commented-out.  Also, when the BackgroundGeolocationService is run due to a BOOT_COMPLETED, there's no way to fetch any kind of user info, such as an authentication_token for your server to authenticate an HTTP request (if you've enabled the HTTP feature).  However, the HTTP request will insert the Android UUID which you *can* use to authenticate the request.  It's up to the developer to map the Android UUID to some particular user on your server.  You may fetch the Android UUID using the standard cordova plugin org.apache.cordova.device (see the documentation there on that API)
parent ca77173d
......@@ -178,10 +178,10 @@ var app = {
distanceFilter: 50,
locationUpdateInterval: 5000,
activityRecognitionInterval: 10000,
stopTimeout: 1,
forceReload: true, // <-- If the user closes the app **while location-tracking is started** , reboot app (WARNING: possibly distruptive to user)
activityType: 'AutomotiveNavigation',
stopOnTerminate: false // <-- Allow the background-service to run headless when user closes the app.
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.
activityType: 'AutomotiveNavigation'
/**
* HTTP Feature: set an url to allow the native background service to POST locations to your server
*
......
......@@ -29,6 +29,7 @@
<source-file src="src/android/BackgroundGeolocationService.java" target-dir="src/com/transistorsoft/cordova/bggeo" />
<source-file src="src/android/ActivityRecognitionService.java" target-dir="src/com/transistorsoft/cordova/bggeo" />
<source-file src="src/android/LocationService.java" target-dir="src/com/transistorsoft/cordova/bggeo" />
<source-file src="src/android/BootReceiver.java" target-dir="src/com/transistorsoft/cordova/bggeo" />
<!-- For SQLite persistence NOT YET IMPLEMENTED
<source-file src="src/android/data/LocationDAO.java" target-dir="src/com/tenforwardconsulting/cordova/bgloc/data" />
......
......@@ -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.IntentFilter;
import android.location.Location;
import android.util.Log;
......@@ -48,7 +49,7 @@ public class BackgroundGeolocationPlugin extends CordovaPlugin {
@Override
protected void pluginInitialize() {
gWebView = this.webView;
// Register for events fired by our IntentService "LocationService"
EventBus.getDefault().register(this);
}
......
......@@ -35,6 +35,7 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings.Secure;
import android.util.Log;
public class BackgroundGeolocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
......@@ -101,7 +102,7 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
/**
* @config {JSONObject} headers For sending location to your server
*/
private JSONObject headers = null;
private JSONObject headers = new JSONObject();
// Flags
private Boolean isEnabled = false;
......@@ -150,6 +151,7 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
Log.i(TAG, " locationUpdateInterval: " + locationUpdateInterval);
Log.i(TAG, " activityRecognitionInterval: " + activityRecognitionInterval);
Log.i(TAG, " stopTimeout: " + stopTimeout);
Log.i(TAG, " stopOnTerminate: " + stopOnTerminate);
Log.i(TAG, " forceReload: " + forceReload);
Log.i(TAG, "----------------------------------------");
......@@ -158,13 +160,6 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
toneGenerator = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
}
// Configure FusedLocationProvider
locationRequest = LocationRequest.create()
.setPriority(translateDesiredAccuracy(desiredAccuracy))
.setInterval(this.locationUpdateInterval)
.setFastestInterval(30000)
.setSmallestDisplacement(distanceFilter);
// Connect to google-play services.
if (ConnectionResult.SUCCESS == GooglePlayServicesUtil.isGooglePlayServicesAvailable(this)) {
Log.i(TAG, "- Connecting to GooglePlayServices...");
......@@ -199,6 +194,13 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
public void onConnected(Bundle arg0) {
Log.i(TAG, "- GooglePlayServices connected");
// Configure FusedLocationProvider
locationRequest = LocationRequest.create()
.setPriority(translateDesiredAccuracy(desiredAccuracy))
.setInterval(this.locationUpdateInterval)
.setFastestInterval(30000)
.setSmallestDisplacement(distanceFilter);
Intent arsIntent = new Intent(this, ActivityRecognitionService.class);
activityRecognitionPI = PendingIntent.getService(this, 0, arsIntent, PendingIntent.FLAG_UPDATE_CURRENT);
......@@ -217,12 +219,12 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
* @param {PausedEvent} event
*/
public void onEventMainThread(PausedEvent event) {
isPaused = event.isPaused;
if (isPaused) {
setPace(isMoving);
} else {
removeLocationUpdates();
}
isPaused = event.isPaused;
if (isPaused) {
setPace(isMoving);
} else {
removeLocationUpdates();
}
}
/**
......@@ -231,7 +233,7 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
* @param {PaceChangeEvent} event
*/
public void onEventMainThread(PaceChangeEvent event) {
setPace(event.isMoving);
setPace(event.isMoving);
}
/**
......@@ -243,6 +245,12 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
String probableActivityName = getActivityName(currentActivity.getType());
Log.i(TAG, "- Activity received: " + probableActivityName + ", confidence: " + currentActivity.getConfidence());
// If configured to stop when user closes app, kill this service.
if (!BackgroundGeolocationPlugin.isActive() && stopOnTerminate) {
stopSelf();
return;
}
boolean wasMoving = isMoving;
boolean nowMoving = false;
......@@ -408,7 +416,15 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
JSONObject data = locationToJson(location);
params.put("location", data);
// Append android UUID to params so that server can map the UUID to some user in your database on server.
// If you've configured the plugin to execute on BOOT, there's no way to append your user's auth-token to the params
// since this BackgroundGeolocationService will be running in "headless" mode.
//
// It's up to you to register this UUID with your system. You can fetch this UUID using the
// Cordova Device plugin org.apache.cordova.device http://plugins.cordova.io/#/package/org.apache.cordova.device
params.put("android_id", Secure.getString(this.getContentResolver(), Secure.ANDROID_ID));
Log.i(TAG, "data: " + params.toString());
StringEntity se = new StringEntity(params.toString());
......@@ -462,7 +478,7 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
}
private void requestLocationUpdates() {
if (!isPaused || !isEnabled) { return; } // <-- Don't engage GPS when app is in foreground
if (!isPaused || !isEnabled) { return; } // <-- Don't engage GPS when app is in foreground
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, locationUpdatePI);
}
......@@ -541,18 +557,18 @@ public class BackgroundGeolocationService extends Service implements GoogleApiCl
}
public static class PausedEvent {
public boolean isPaused;
public PausedEvent(boolean paused) {
isPaused = paused;
}
public boolean isPaused;
public PausedEvent(boolean paused) {
isPaused = paused;
}
}
public static class PaceChangeEvent {
public boolean isMoving;
public PaceChangeEvent(boolean moving) {
isMoving = moving;
}
}
public static class PaceChangeEvent {
public boolean isMoving;
public PaceChangeEvent(boolean moving) {
isMoving = moving;
}
}
class StationaryLocation extends Location {
......
package com.transistorsoft.cordova.bggeo;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.ActivityRecognition;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
/**
* This boot receiver is meant to handle the case where device is first booted after power up. This will initiate
* Google Play's ActivityRecognition API, whose events will be sent to BackgroundGeolocationService as usual.
* @author chris
* This boot receiver is meant to handle the case where device is first booted after power up.
* This boot the headless BackgroundGeolocationService as configured by this class.
* @author chris scott
*
*/
public class BootReceiver extends BroadcastReceiver implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public class BootReceiver extends BroadcastReceiver {
private static final String TAG = "BackgroundGeolocation";
private GoogleApiClient googleApiClient;
private PendingIntent locationUpdateService;
/**
* 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 PendingResult pendingResult;
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'}";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "- BootReceiver auto-running ActivityRecognition system");
Log.i(TAG, "- BootReceiver booting service");
// GoogleApiClient connection is asynchronous process. @see #onConnected
pendingResult = goAsync();
Intent backgroundServiceIntent = new Intent(context, BackgroundGeolocationService.class);
// Connect to google-play services.
if (ConnectionResult.SUCCESS == GooglePlayServicesUtil.isGooglePlayServicesAvailable(context)) {
Log.i(TAG, "- Connecting to GooglePlayServices...");
googleApiClient = new GoogleApiClient.Builder(context)
.addApi(ActivityRecognition.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
googleApiClient.connect();
} else {
Log.e(TAG, "- GooglePlayServices unavailable");
}
// 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);
// This is the IntentService we'll provide to google-play API.
locationUpdateService = PendingIntent.getService(context, 0, new Intent(context, LocationService.class), PendingIntent.FLAG_UPDATE_CURRENT);
}
private void requestActivityUpdates() {
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(googleApiClient, activityRecognitionInterval, locationUpdateService);
// Start the service.
context.startService(backgroundServiceIntent);
}
@Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
pendingResult.finish();
}
@Override
public void onConnected(Bundle arg0) {
requestActivityUpdates();
pendingResult.finish();
}
@Override
public void onConnectionSuspended(int arg0) {
// TODO Auto-generated method stub
pendingResult.finish();
}
}
\ No newline at end of file
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