/*
* Copyright 2011 Greg Milette and Adam Stroud
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package root.gast.playground.location;
import root.gast.location.LocationBroadcastReceiver;
import android.content.Context;
import android.location.Location;
import android.util.Log;
/**
* Broadcast receiver that will perform filtering algorithms on location information
* that is received from the location service.
*
* @author Adam Stroud <<a href="mailto:adam.stroud@gmail.com">adam.stroud@gmail.com</a>>
*/
public abstract class FilteringLocationBroadcastReceiver extends LocationBroadcastReceiver
{
private static final String TAG = "FilteringLocationBroadcastReceiver";
private static final int TIME_THRESHOLD = 30000; // 30 sec.
private static final int ACCURACY_PERCENT = 10;
private static final int VELOCITY_THRESHOLD = 200; // m/s
@Override
public void onLocationChanged(Context context, Location location)
{
Point lastPoint =
PointDatabaseManager.getInstance(context).retrieveLatestPoint();
if (lastPoint == null)
{
Log.d(TAG, "Adding point");
onFilteredLocationChanged(context, location);
}
else
{
float currentAccuracy = location.getAccuracy();
float previousAccuracy = lastPoint.getAccuracy();
Point point =
PointDatabaseManager.getInstance(context).retrieveLatestPoint();
// True IFF accuracy is greater, but limited to 10% of the previous
// accuracy and new point was generated by the same provider
float accuracyDifference = Math.abs(previousAccuracy - currentAccuracy);
boolean lowerAccuracyAcceptable = currentAccuracy > previousAccuracy
&& lastPoint.getProvider().equals(location.getProvider())
&& (accuracyDifference <= previousAccuracy / ACCURACY_PERCENT);
float[] results = new float[1];
Location.distanceBetween(point.getLatitude(),
point.getLongitude(),
location.getLatitude(),
location.getLongitude(),
results);
float velocity =
results[0] / ((location.getTime() - point.getTime()) / 1000);
// Accept the new point if:
// * The velocity seems reasonable (point did not jump)and one of the
// following:
// * It has a better accuracy
// * The app has not accepted a point in TIME_THRESHOLD
// * It's worse accuracy is still acceptable
if (velocity <= VELOCITY_THRESHOLD
&& (currentAccuracy < previousAccuracy
|| (location.getTime() - lastPoint.getTime()) > TIME_THRESHOLD
|| lowerAccuracyAcceptable))
{
Log.d(TAG, "Adding point");
onFilteredLocationChanged(context, location);
}
else
{
Log.d(TAG, "Ignoring point");
}
}
}
protected abstract void onFilteredLocationChanged(Context context,
Location location);
}