package interdroid.swan.sensors.impl;
import interdroid.swan.R;
import interdroid.swan.sensors.AbstractConfigurationActivity;
import interdroid.swan.sensors.AbstractSwanSensor;
import java.lang.reflect.Field;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
/**
* A sensor for location.
*
* @author nick <palmer@cs.vu.nl>
*
*/
public class LocationSensor extends AbstractSwanSensor {
private static final String TAG = "Location Sensor";
/**
* The configuration activity for this sensor.
*
* @author nick <palmer@cs.vu.nl>
*
*/
public static class ConfigurationActivity extends
AbstractConfigurationActivity {
@Override
public final int getPreferencesXML() {
return R.xml.location_preferences;
}
}
/**
* Location field name.
*/
public static final String LOCATION_FIELD = "location";
/**
* Accuracy field name.
*/
public static final String ACCURACY_FIELD = "accuracy";
/**
* Bearing field name.
*/
public static final String BEARING_FIELD = "bearing";
/**
* Latitude field name.
*/
public static final String LATITUDE_FIELD = "latitude";
/**
* Longitude field name.
*/
public static final String LONGITUDE_FIELD = "longitude";
/**
* Altitude field name.
*/
public static final String ALTITUDE_FIELD = "altitude";
/**
* Speed field name.
*/
public static final String SPEED_FIELD = "speed";
/**
* Minimum acceptable distance.
*/
public static final String MIN_DISTANCE = "min_distance";
/**
* Minimum acceptable time.
*/
public static final String MIN_TIME = "min_time";
/**
* The type of provider desired.
*/
public static final String PROVIDER = "provider";
/**
* The current provider we are using.
*/
private String currentProvider;
/**
* The location manager we use.
*/
private LocationManager locationManager;
/**
* The location listener.
*/
private LocationListener locationListener = new LocationListener() {
public void onLocationChanged(final Location location) {
long now = System.currentTimeMillis();
Log.d(TAG, "Location: " + location.getLatitude() + ", "
+ location.getLongitude());
putValueTrimSize(LATITUDE_FIELD, null, now, location.getLatitude());
putValueTrimSize(LONGITUDE_FIELD, null, now, location.getLongitude());
putValueTrimSize(ALTITUDE_FIELD, null, now, location.getAltitude());
putValueTrimSize(SPEED_FIELD, null, now, location.getSpeed());
putValueTrimSize(BEARING_FIELD, null, now, location.getBearing());
putValueTrimSize(ACCURACY_FIELD, null, now, location.getAccuracy());
}
public void onProviderDisabled(final String provider) {
Log.d(TAG, "provider disabled: " + provider + ". I am using: "
+ currentProvider);
if (provider.equals(currentProvider)) {
Log.w(TAG, "location sensor disabled due to lack of provider");
}
}
public void onProviderEnabled(final String provider) {
Log.d(TAG, "provider enabled: " + provider);
}
public void onStatusChanged(final String provider, final int status,
final Bundle extras) {
if (provider.equals(currentProvider)
&& status != LocationProvider.AVAILABLE) {
Log.w(TAG,
"location sensor disabled because sensor unavailable");
}
}
};
@Override
public final String[] getValuePaths() {
return new String[] { LOCATION_FIELD, LATITUDE_FIELD, LONGITUDE_FIELD,
ALTITUDE_FIELD, SPEED_FIELD, BEARING_FIELD, ACCURACY_FIELD };
}
@Override
public final void initDefaultConfiguration(final Bundle defaults) {
defaults.putLong(MIN_TIME, 0);
defaults.putLong(MIN_DISTANCE, 0);
defaults.putString(PROVIDER, LocationManager.NETWORK_PROVIDER);
}
@Override
public final void onConnected() {
SENSOR_NAME = "Location Sensor";
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
@Override
public final void register(final String id, final String valuePath,
final Bundle configuration) {
if (registeredConfigurations.size() == 1) {
updateListener();
}
}
/**
* Updates the listener.
*/
private void updateListener() {
long minTime = Long.MAX_VALUE;
long minDistance = Long.MAX_VALUE;
String mostAccurateProvider;
String passiveProvider = null;
// Reflect out PASSIVE_PROVIDER so we can still run on 7.
try {
Field passive = LocationManager.class.getField("PASSIVE_PROVIDER");
passiveProvider = (String) passive.get(null);
mostAccurateProvider = passiveProvider;
} catch (Exception e) {
Log.w(TAG, "Caught exception checking for PASSIVE_PROVIDER.", e);
mostAccurateProvider = LocationManager.NETWORK_PROVIDER;
}
for (Bundle configuration : registeredConfigurations.values()) {
if (configuration.containsKey(MIN_TIME)) {
minTime = Math.min(minTime, configuration.getLong(MIN_TIME));
}
if (configuration.containsKey(MIN_DISTANCE)) {
minDistance = Math.min(minDistance,
configuration.getLong(MIN_DISTANCE));
}
if (configuration.containsKey(PROVIDER)) {
if (mostAccurateProvider.equals(passiveProvider)) {
// if current is passive, anything is better
mostAccurateProvider = configuration.getString(PROVIDER);
} else if (LocationManager.NETWORK_PROVIDER
.equals(mostAccurateProvider)
&& LocationManager.GPS_PROVIDER.equals(configuration
.getString(PROVIDER))) {
// if current is network, only gps is better
mostAccurateProvider = LocationManager.GPS_PROVIDER;
}
// if it isn't PASSIVE or NETWORK, we can't do any better, it
// must be GPS
}
}
if (minTime == Long.MAX_VALUE) {
minTime = mDefaultConfiguration.getLong(MIN_TIME);
}
if (minDistance == Long.MAX_VALUE) {
minDistance = mDefaultConfiguration.getLong(MIN_DISTANCE);
}
locationManager.removeUpdates(locationListener);
locationManager.requestLocationUpdates(mostAccurateProvider, minTime,
minDistance, locationListener, Looper.getMainLooper());
}
@Override
public final void unregister(final String id) {
if (registeredConfigurations.size() == 0) {
locationManager.removeUpdates(locationListener);
} else {
updateListener();
}
}
@Override
public void onDestroySensor() {
super.onDestroySensor();
}
// @Override
// public List<TimestampedValue> getValues(String id, long now, long timespan) {
// if (LOCATION_FIELD.equals(registeredValuePaths.get(id))) {
// List<TimestampedValue> latitudes = getValuesForValuePath(
// LATITUDE_FIELD, null, now, timespan);
// List<TimestampedValue> longitudes = getValuesForValuePath(
// LONGITUDE_FIELD, null, now, timespan);
// List<TimestampedValue> altitudes = getValuesForValuePath(
// ALTITUDE_FIELD, null, now, timespan);
// List<TimestampedValue> speeds = getValuesForValuePath(SPEED_FIELD,
// null, now, timespan);
// List<TimestampedValue> bearings = getValuesForValuePath(
// BEARING_FIELD, null, now, timespan);
// List<TimestampedValue> accuracies = getValuesForValuePath(
// ACCURACY_FIELD, null, now, timespan);
// for (int i = 0; i < latitudes.size(); i++) {
// Location location = new Location("SWAN Location Sensor");
// location.setLatitude((Double) latitudes.get(i).getValue());
// location.setLongitude((Double) longitudes.get(i).getValue());
// location.setSpeed((Float) speeds.get(i).getValue());
// location.setAltitude((Double) altitudes.get(i).getValue());
// location.setBearing((Float) bearings.get(i).getValue());
// location.setAccuracy((Float) accuracies.get(i).getValue());
//
// latitudes.set(i, new TimestampedValue(location, latitudes
// .get(i).getTimestamp()));
// }
// return latitudes;
// }
// return super.getValues(id, now, timespan);
// }
}