721 lines
23 KiB
Java
721 lines
23 KiB
Java
// Copyright 2007 The Android Open Source Project
|
|
|
|
package com.android.internal.location;
|
|
|
|
import org.xmlpull.v1.XmlPullParser;
|
|
import org.xmlpull.v1.XmlPullParserException;
|
|
import org.xmlpull.v1.XmlPullParserFactory;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileReader;
|
|
import java.io.IOException;
|
|
import java.io.Reader;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.StringTokenizer;
|
|
|
|
import android.location.Criteria;
|
|
import android.location.Location;
|
|
import android.location.LocationProviderImpl;
|
|
import android.os.Bundle;
|
|
import android.util.Config;
|
|
import android.util.Log;
|
|
|
|
/**
|
|
* A dummy provider that returns positions interpolated from a sequence
|
|
* of caller-supplied waypoints. The waypoints are supplied as a
|
|
* String containing one or more numeric quadruples of the form:
|
|
* <br>
|
|
* <code>
|
|
* <time in millis> <latitude> <longitude> <altitude>
|
|
* </code>
|
|
*
|
|
* <p> The waypoints must be supplied in increasing timestamp order.
|
|
*
|
|
* <p> The time at which the provider is constructed is considered to
|
|
* be time 0, and further requests for positions will return a
|
|
* position that is linearly interpolated between the waypoints whose
|
|
* timestamps are closest to the amount of wall clock time that has
|
|
* elapsed since time 0.
|
|
*
|
|
* <p> Following the time of the last waypoint, the position of that
|
|
* waypoint will continue to be returned indefinitely.
|
|
*
|
|
* {@hide}
|
|
*/
|
|
public class TrackProvider extends LocationProviderImpl {
|
|
static final String LOG_TAG = "TrackProvider";
|
|
|
|
private static final long INTERVAL = 1000L;
|
|
|
|
private boolean mEnabled = true;
|
|
|
|
private double mLatitude;
|
|
private double mLongitude;
|
|
private boolean mHasAltitude;
|
|
private boolean mHasBearing;
|
|
private boolean mHasSpeed;
|
|
private double mAltitude;
|
|
private float mBearing;
|
|
private float mSpeed;
|
|
private Bundle mExtras;
|
|
|
|
private long mBaseTime;
|
|
private long mLastTime = -1L;
|
|
private long mTime;
|
|
|
|
private long mMinTime;
|
|
private long mMaxTime;
|
|
|
|
private List<Waypoint> mWaypoints = new ArrayList<Waypoint>();
|
|
private int mWaypointIndex = 0;
|
|
|
|
private boolean mRequiresNetwork = false;
|
|
private boolean mRequiresSatellite = false;
|
|
private boolean mRequiresCell = false;
|
|
private boolean mHasMonetaryCost = false;
|
|
private boolean mSupportsAltitude = true;
|
|
private boolean mSupportsSpeed = true;
|
|
private boolean mSupportsBearing = true;
|
|
private boolean mRepeat = false;
|
|
private int mPowerRequirement = Criteria.POWER_LOW;
|
|
private int mAccuracy = Criteria.ACCURACY_COARSE;
|
|
|
|
private float mTrackSpeed = 100.0f; // km/hr - default for kml tracks
|
|
|
|
private Location mInitialLocation;
|
|
|
|
private void close(Reader rdr) {
|
|
try {
|
|
if (rdr != null) {
|
|
rdr.close();
|
|
}
|
|
} catch (IOException e) {
|
|
Log.w(LOG_TAG, "Exception closing reader", e);
|
|
}
|
|
}
|
|
|
|
public void readTrack(File trackFile) {
|
|
BufferedReader br = null;
|
|
try {
|
|
br = new BufferedReader(new FileReader(trackFile), 8192);
|
|
String s;
|
|
|
|
long lastTime = -Long.MAX_VALUE;
|
|
while ((s = br.readLine()) != null) {
|
|
String[] tokens = s.split("\\s+");
|
|
if (tokens.length != 4 && tokens.length != 6) {
|
|
Log.e(LOG_TAG, "Got track \"" + s +
|
|
"\", wanted <time> <long> <lat> <alt> [<bearing> <speed>]");
|
|
continue;
|
|
}
|
|
long time;
|
|
double longitude, latitude, altitude;
|
|
try {
|
|
time = Long.parseLong(tokens[0]);
|
|
longitude = Double.parseDouble(tokens[1]);
|
|
latitude = Double.parseDouble(tokens[2]);
|
|
altitude = Double.parseDouble(tokens[3]);
|
|
} catch (NumberFormatException e) {
|
|
Log.e(LOG_TAG, "Got track \"" + s +
|
|
"\", wanted <time> <long> <lat> <alt> " +
|
|
"[<bearing> <speed>]", e);
|
|
continue;
|
|
}
|
|
|
|
Waypoint w = new Waypoint(getName(), time, latitude, longitude, altitude);
|
|
if (tokens.length >= 6) {
|
|
float bearing, speed;
|
|
try {
|
|
bearing = Float.parseFloat(tokens[4]);
|
|
speed = Float.parseFloat(tokens[5]);
|
|
w.setBearing(bearing);
|
|
w.setSpeed(speed);
|
|
} catch (NumberFormatException e) {
|
|
Log.e(LOG_TAG, "Ignoring bearing and speed \"" +
|
|
tokens[4] + "\", \"" + tokens[5] + "\"", e);
|
|
}
|
|
}
|
|
|
|
if (mInitialLocation == null) {
|
|
mInitialLocation = w.getLocation();
|
|
}
|
|
|
|
// Ignore waypoints whose time is less than or equal to 0 or
|
|
// the time of the previous waypoint
|
|
if (time < 0) {
|
|
Log.e(LOG_TAG, "Ignoring waypoint at negative time=" + time);
|
|
continue;
|
|
}
|
|
if (time <= lastTime) {
|
|
Log.e(LOG_TAG, "Ignoring waypoint at time=" + time +
|
|
" (< " + lastTime + ")");
|
|
continue;
|
|
}
|
|
|
|
mWaypoints.add(w);
|
|
lastTime = time;
|
|
}
|
|
|
|
setTimes();
|
|
return;
|
|
} catch (IOException e) {
|
|
Log.e(LOG_TAG, "Exception reading track file", e);
|
|
mWaypoints.clear();
|
|
} finally {
|
|
close(br);
|
|
}
|
|
}
|
|
|
|
public void readKml(File kmlFile) {
|
|
FileReader kmlReader = null;
|
|
try {
|
|
kmlReader = new FileReader(kmlFile);
|
|
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
|
|
XmlPullParser xpp = factory.newPullParser();
|
|
xpp.setInput(kmlReader);
|
|
|
|
// Concatenate the text of each <coordinates> tag
|
|
boolean inCoordinates = false;
|
|
StringBuilder sb = new StringBuilder();
|
|
int eventType = xpp.getEventType();
|
|
do {
|
|
if (eventType == XmlPullParser.START_DOCUMENT) {
|
|
// do nothing
|
|
} else if (eventType == XmlPullParser.END_DOCUMENT) {
|
|
// do nothing
|
|
} else if (eventType == XmlPullParser.START_TAG) {
|
|
String startTagName = xpp.getName();
|
|
if (startTagName.equals("coordinates")) {
|
|
inCoordinates = true;
|
|
}
|
|
} else if (eventType == XmlPullParser.END_TAG) {
|
|
String endTagName = xpp.getName();
|
|
if (endTagName.equals("coordinates")) {
|
|
inCoordinates = false;
|
|
}
|
|
} else if (eventType == XmlPullParser.TEXT) {
|
|
if (inCoordinates) {
|
|
sb.append(xpp.getText());
|
|
sb.append(' ');
|
|
}
|
|
}
|
|
eventType = xpp.next();
|
|
} while (eventType != XmlPullParser.END_DOCUMENT);
|
|
|
|
String coordinates = sb.toString();
|
|
|
|
// Parse the "lon,lat,alt" triples and supply times
|
|
// for each waypoint based on a constant speed
|
|
Location loc = null;
|
|
double KM_PER_HOUR = mTrackSpeed;
|
|
double KM_PER_METER = 1.0 / 1000.0;
|
|
double MILLIS_PER_HOUR = 60.0 * 60.0 * 1000.0;
|
|
double MILLIS_PER_METER =
|
|
(1.0 / KM_PER_HOUR) * (KM_PER_METER) * (MILLIS_PER_HOUR);
|
|
long time = 0L;
|
|
|
|
StringTokenizer st = new StringTokenizer(coordinates, ", ");
|
|
while (st.hasMoreTokens()) {
|
|
try {
|
|
String lon = st.nextToken();
|
|
String lat = st.nextToken();
|
|
String alt = st.nextToken();
|
|
if (Config.LOGD) {
|
|
Log.d(LOG_TAG,
|
|
"lon=" + lon + ", lat=" + lat + ", alt=" + alt);
|
|
}
|
|
|
|
double nLongitude = Double.parseDouble(lon);
|
|
double nLatitude = Double.parseDouble(lat);
|
|
double nAltitude = Double.parseDouble(alt);
|
|
|
|
Location nLoc = new Location(getName());
|
|
nLoc.setLatitude(nLatitude);
|
|
nLoc.setLongitude(nLongitude);
|
|
if (loc != null) {
|
|
double distance = loc.distanceTo(nLoc);
|
|
if (Config.LOGD) {
|
|
Log.d(LOG_TAG, "distance = " + distance);
|
|
}
|
|
time += (long) (distance * MILLIS_PER_METER);
|
|
}
|
|
|
|
Waypoint w = new Waypoint(getName(), time,
|
|
nLatitude, nLongitude, nAltitude);
|
|
if (supportsSpeed()) {
|
|
w.setSpeed(mTrackSpeed);
|
|
}
|
|
if (supportsBearing()) {
|
|
w.setBearing(0.0f);
|
|
}
|
|
mWaypoints.add(w);
|
|
|
|
if (mInitialLocation == null) {
|
|
mInitialLocation = w.getLocation();
|
|
}
|
|
|
|
loc = nLoc;
|
|
} catch (NumberFormatException nfe) {
|
|
Log.e(LOG_TAG, "Got NumberFormatException reading KML data: " +
|
|
nfe, nfe);
|
|
}
|
|
}
|
|
|
|
setTimes();
|
|
return;
|
|
} catch (IOException ioe) {
|
|
mWaypoints.clear();
|
|
Log.e(LOG_TAG, "Exception reading KML data: " + ioe, ioe);
|
|
// fall through
|
|
} catch (XmlPullParserException xppe) {
|
|
mWaypoints.clear();
|
|
Log.e(LOG_TAG, "Exception reading KML data: " + xppe, xppe);
|
|
// fall through
|
|
} finally {
|
|
close(kmlReader);
|
|
}
|
|
}
|
|
|
|
public void readNmea(String name, File file) {
|
|
BufferedReader br = null;
|
|
try {
|
|
br = new BufferedReader(new FileReader(file), 8192);
|
|
String s;
|
|
|
|
String provider = getName();
|
|
NmeaParser parser = new NmeaParser(name);
|
|
while ((s = br.readLine()) != null) {
|
|
boolean newWaypoint = parser.parseSentence(s);
|
|
if (newWaypoint) {
|
|
Location loc = parser.getLocation();
|
|
Waypoint w = new Waypoint(loc);
|
|
mWaypoints.add(w);
|
|
// Log.i(TAG, "Got waypoint " + w);
|
|
}
|
|
}
|
|
|
|
setTimes();
|
|
return;
|
|
} catch (IOException ioe) {
|
|
Log.e(LOG_TAG, "Exception reading NMEA data: " + ioe);
|
|
mWaypoints.clear();
|
|
} finally {
|
|
close(br);
|
|
}
|
|
}
|
|
|
|
private static boolean booleanVal(String tf) {
|
|
return (tf == null) || (tf.equalsIgnoreCase("true"));
|
|
}
|
|
|
|
private static int intVal(String val) {
|
|
try {
|
|
return (val == null) ? 0 : Integer.parseInt(val);
|
|
} catch (NumberFormatException nfe) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private static float floatVal(String val) {
|
|
try {
|
|
return (val == null) ? 0 : Float.parseFloat(val);
|
|
} catch (NumberFormatException nfe) {
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
public void readProperties(File propertiesFile) {
|
|
BufferedReader br = null;
|
|
if (!propertiesFile.exists()) {
|
|
return;
|
|
}
|
|
try {
|
|
if (Config.LOGD) {
|
|
Log.d(LOG_TAG, "Loading properties file " +
|
|
propertiesFile.getPath());
|
|
}
|
|
br = new BufferedReader(new FileReader(propertiesFile), 8192);
|
|
|
|
String s;
|
|
while ((s = br.readLine()) != null) {
|
|
StringTokenizer st = new StringTokenizer(s);
|
|
String command = null;
|
|
String value = null;
|
|
if (!st.hasMoreTokens()) {
|
|
continue;
|
|
}
|
|
command = st.nextToken();
|
|
if (st.hasMoreTokens()) {
|
|
value = st.nextToken();
|
|
}
|
|
|
|
if (command.equalsIgnoreCase("requiresNetwork")) {
|
|
setRequiresNetwork(booleanVal(value));
|
|
} else if (command.equalsIgnoreCase("requiresSatellite")) {
|
|
setRequiresSatellite(booleanVal(value));
|
|
} else if (command.equalsIgnoreCase("requiresCell")) {
|
|
setRequiresCell(booleanVal(value));
|
|
} else if (command.equalsIgnoreCase("hasMonetaryCost")) {
|
|
setHasMonetaryCost(booleanVal(value));
|
|
} else if (command.equalsIgnoreCase("supportsAltitude")) {
|
|
setSupportsAltitude(booleanVal(value));
|
|
} else if (command.equalsIgnoreCase("supportsBearing")) {
|
|
setSupportsBearing(booleanVal(value));
|
|
} else if (command.equalsIgnoreCase("repeat")) {
|
|
setRepeat(booleanVal(value));
|
|
} else if (command.equalsIgnoreCase("supportsSpeed")) {
|
|
setSupportsSpeed(booleanVal(value));
|
|
} else if (command.equalsIgnoreCase("powerRequirement")) {
|
|
setPowerRequirement(intVal(value));
|
|
} else if (command.equalsIgnoreCase("accuracy")) {
|
|
setAccuracy(intVal(value));
|
|
} else if (command.equalsIgnoreCase("trackspeed")) {
|
|
setTrackSpeed(floatVal(value));
|
|
} else {
|
|
Log.e(LOG_TAG, "Unknown command \"" + command + "\"");
|
|
}
|
|
}
|
|
} catch (IOException ioe) {
|
|
Log.e(LOG_TAG, "IOException reading properties file " +
|
|
propertiesFile.getPath(), ioe);
|
|
} finally {
|
|
try {
|
|
if (br != null) {
|
|
br.close();
|
|
}
|
|
} catch (IOException e) {
|
|
Log.w(LOG_TAG, "IOException closing properties file " +
|
|
propertiesFile.getPath(), e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public TrackProvider(String name) {
|
|
super(name);
|
|
setTimes();
|
|
}
|
|
|
|
public TrackProvider(String name, File file) {
|
|
this(name);
|
|
|
|
String filename = file.getName();
|
|
if (filename.endsWith("kml")) {
|
|
readKml(file);
|
|
} else if (filename.endsWith("nmea")) {
|
|
readNmea(getName(), file);
|
|
} else if (filename.endsWith("track")) {
|
|
readTrack(file);
|
|
} else {
|
|
Log.e(LOG_TAG, "Can't initialize TrackProvider from file " +
|
|
filename + " (not *kml, *nmea, or *track)");
|
|
}
|
|
setTimes();
|
|
}
|
|
|
|
private void setTimes() {
|
|
mBaseTime = System.currentTimeMillis();
|
|
if (mWaypoints.size() >= 2) {
|
|
mMinTime = mWaypoints.get(0).getTime();
|
|
mMaxTime = mWaypoints.get(mWaypoints.size() - 1).getTime();
|
|
} else {
|
|
mMinTime = mMaxTime = 0;
|
|
}
|
|
}
|
|
|
|
private double interp(double d0, double d1, float frac) {
|
|
return d0 + frac * (d1 - d0);
|
|
}
|
|
|
|
private void update() {
|
|
// Don't update the position at all unless INTERVAL milliseconds
|
|
// have passed since the last request
|
|
long time = System.currentTimeMillis() - mBaseTime;
|
|
if (time - mLastTime < INTERVAL) {
|
|
return;
|
|
}
|
|
|
|
List<Waypoint> waypoints = mWaypoints;
|
|
if (waypoints == null) {
|
|
return;
|
|
}
|
|
int size = waypoints.size();
|
|
if (size < 2) {
|
|
return;
|
|
}
|
|
|
|
long t = time;
|
|
if (t < mMinTime) {
|
|
t = mMinTime;
|
|
}
|
|
if (mRepeat) {
|
|
t -= mMinTime;
|
|
long deltaT = mMaxTime - mMinTime;
|
|
t %= 2 * deltaT;
|
|
if (t > deltaT) {
|
|
t = 2 * deltaT - t;
|
|
}
|
|
t += mMinTime;
|
|
} else if (t > mMaxTime) {
|
|
t = mMaxTime;
|
|
}
|
|
|
|
// Locate the time interval for the current time
|
|
// We slide the window since we don't expect to move
|
|
// much between calls
|
|
|
|
Waypoint w0 = waypoints.get(mWaypointIndex);
|
|
Waypoint w1 = waypoints.get(mWaypointIndex + 1);
|
|
|
|
// If the right end of the current interval is too early,
|
|
// move forward to the next waypoint
|
|
while (t > w1.getTime()) {
|
|
w0 = w1;
|
|
w1 = waypoints.get(++mWaypointIndex + 1);
|
|
}
|
|
// If the left end of the current interval is too late,
|
|
// move back to the previous waypoint
|
|
while (t < w0.getTime()) {
|
|
w1 = w0;
|
|
w0 = waypoints.get(--mWaypointIndex);
|
|
}
|
|
|
|
// Now we know that w0.mTime <= t <= w1.mTime
|
|
long w0Time = w0.getTime();
|
|
long w1Time = w1.getTime();
|
|
long dt = w1Time - w0Time;
|
|
|
|
float frac = (dt == 0) ? 0 : ((float) (t - w0Time) / dt);
|
|
mLatitude = interp(w0.getLatitude(), w1.getLatitude(), frac);
|
|
mLongitude = interp(w0.getLongitude(), w1.getLongitude(), frac);
|
|
mHasAltitude = w0.hasAltitude() && w1.hasAltitude();
|
|
if (mSupportsAltitude && mHasAltitude) {
|
|
mAltitude = interp(w0.getAltitude(), w1.getAltitude(), frac);
|
|
}
|
|
if (mSupportsBearing) {
|
|
mHasBearing = frac <= 0.5f ? w0.hasBearing() : w1.hasBearing();
|
|
if (mHasBearing) {
|
|
mBearing = frac <= 0.5f ? w0.getBearing() : w1.getBearing();
|
|
}
|
|
}
|
|
if (mSupportsSpeed) {
|
|
mHasSpeed = frac <= 0.5f ? w0.hasSpeed() : w1.hasSpeed();
|
|
if (mHasSpeed) {
|
|
mSpeed = frac <= 0.5f ? w0.getSpeed() : w1.getSpeed();
|
|
}
|
|
}
|
|
mLastTime = time;
|
|
mTime = time;
|
|
}
|
|
|
|
public void setRequiresNetwork(boolean requiresNetwork) {
|
|
mRequiresNetwork = requiresNetwork;
|
|
}
|
|
|
|
@Override public boolean requiresNetwork() {
|
|
return mRequiresNetwork;
|
|
}
|
|
|
|
public void setRequiresSatellite(boolean requiresSatellite) {
|
|
mRequiresSatellite = requiresSatellite;
|
|
}
|
|
|
|
@Override public boolean requiresSatellite() {
|
|
return mRequiresSatellite;
|
|
}
|
|
|
|
public void setRequiresCell(boolean requiresCell) {
|
|
mRequiresCell = requiresCell;
|
|
}
|
|
|
|
@Override public boolean requiresCell() {
|
|
return mRequiresCell;
|
|
}
|
|
|
|
public void setHasMonetaryCost(boolean hasMonetaryCost) {
|
|
mHasMonetaryCost = hasMonetaryCost;
|
|
}
|
|
|
|
@Override public boolean hasMonetaryCost() {
|
|
return mHasMonetaryCost;
|
|
}
|
|
|
|
public void setSupportsAltitude(boolean supportsAltitude) {
|
|
mSupportsAltitude = supportsAltitude;
|
|
}
|
|
|
|
@Override public boolean supportsAltitude() {
|
|
return mSupportsAltitude;
|
|
}
|
|
|
|
public void setSupportsSpeed(boolean supportsSpeed) {
|
|
mSupportsSpeed = supportsSpeed;
|
|
}
|
|
|
|
@Override public boolean supportsSpeed() {
|
|
return mSupportsSpeed;
|
|
}
|
|
|
|
public void setSupportsBearing(boolean supportsBearing) {
|
|
mSupportsBearing = supportsBearing;
|
|
}
|
|
|
|
@Override public boolean supportsBearing() {
|
|
return mSupportsBearing;
|
|
}
|
|
|
|
public void setRepeat(boolean repeat) {
|
|
mRepeat = repeat;
|
|
}
|
|
|
|
public void setPowerRequirement(int powerRequirement) {
|
|
if (powerRequirement < Criteria.POWER_LOW ||
|
|
powerRequirement > Criteria.POWER_HIGH) {
|
|
throw new IllegalArgumentException("powerRequirement = " +
|
|
powerRequirement);
|
|
}
|
|
mPowerRequirement = powerRequirement;
|
|
}
|
|
|
|
@Override public int getPowerRequirement() {
|
|
return mPowerRequirement;
|
|
}
|
|
|
|
public void setAccuracy(int accuracy) {
|
|
mAccuracy = accuracy;
|
|
}
|
|
|
|
@Override public int getAccuracy() {
|
|
return mAccuracy;
|
|
}
|
|
|
|
public void setTrackSpeed(float trackSpeed) {
|
|
mTrackSpeed = trackSpeed;
|
|
}
|
|
|
|
@Override public void enable() {
|
|
mEnabled = true;
|
|
}
|
|
|
|
@Override public void disable() {
|
|
mEnabled = false;
|
|
}
|
|
|
|
@Override public boolean isEnabled() {
|
|
return mEnabled;
|
|
}
|
|
|
|
@Override public int getStatus(Bundle extras) {
|
|
return AVAILABLE;
|
|
}
|
|
|
|
@Override public boolean getLocation(Location l) {
|
|
if (mEnabled) {
|
|
update();
|
|
l.setProvider(getName());
|
|
l.setTime(mTime + mBaseTime);
|
|
l.setLatitude(mLatitude);
|
|
l.setLongitude(mLongitude);
|
|
if (mSupportsAltitude && mHasAltitude) {
|
|
l.setAltitude(mAltitude);
|
|
}
|
|
if (mSupportsBearing && mHasBearing) {
|
|
l.setBearing(mBearing);
|
|
}
|
|
if (mSupportsSpeed && mHasSpeed) {
|
|
l.setSpeed(mSpeed);
|
|
}
|
|
if (mExtras != null) {
|
|
l.setExtras(mExtras);
|
|
}
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public Location getInitialLocation() {
|
|
return mInitialLocation;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A simple tuple of (time stamp, latitude, longitude, altitude), plus optional
|
|
* extras.
|
|
*
|
|
* {@hide}
|
|
*/
|
|
class Waypoint {
|
|
public Location mLocation;
|
|
|
|
public Waypoint(Location location) {
|
|
mLocation = location;
|
|
}
|
|
|
|
public Waypoint(String providerName, long time, double latitude, double longitude,
|
|
double altitude) {
|
|
mLocation = new Location(providerName);
|
|
mLocation.setTime(time);
|
|
mLocation.setLatitude(latitude);
|
|
mLocation.setLongitude(longitude);
|
|
mLocation.setAltitude(altitude);
|
|
}
|
|
|
|
public long getTime() {
|
|
return mLocation.getTime();
|
|
}
|
|
|
|
public double getLatitude() {
|
|
return mLocation.getLatitude();
|
|
}
|
|
|
|
public double getLongitude() {
|
|
return mLocation.getLongitude();
|
|
}
|
|
|
|
public boolean hasAltitude() {
|
|
return mLocation.hasAltitude();
|
|
}
|
|
|
|
public double getAltitude() {
|
|
return mLocation.getAltitude();
|
|
}
|
|
|
|
public boolean hasBearing() {
|
|
return mLocation.hasBearing();
|
|
}
|
|
|
|
public void setBearing(float bearing) {
|
|
mLocation.setBearing(bearing);
|
|
}
|
|
|
|
public float getBearing() {
|
|
return mLocation.getBearing();
|
|
}
|
|
|
|
public boolean hasSpeed() {
|
|
return mLocation.hasSpeed();
|
|
}
|
|
|
|
public void setSpeed(float speed) {
|
|
mLocation.setSpeed(speed);
|
|
}
|
|
|
|
public float getSpeed() {
|
|
return mLocation.getSpeed();
|
|
}
|
|
|
|
public Bundle getExtras() {
|
|
return mLocation.getExtras();
|
|
}
|
|
|
|
public Location getLocation() {
|
|
return new Location(mLocation);
|
|
}
|
|
|
|
@Override public String toString() {
|
|
return "Waypoint[mLocation=" + mLocation + "]";
|
|
}
|
|
}
|