Improve Location object.
Add getElapsedRealtimeNano(): Currently Location just has getTime() and setTime() based on UTC time. This is entirely unreliable since it is not guaranteed monotonic. There is a lot of code that compares fix age based on deltas - and it is all broken in the case of a system clock change. System clock can change when switching cellular networks (and in some cases when switching towers). Document the meaning of getAccuracy(): It is the horizontal, 95% confidence radius. Make some fields mandatory if they are reported by a LocationProvider: All Locations returned by a LocationProvider must include at the minimum a lat, long, timestamps, and accuracy. This is necessary to perform fused location. There are no public API's for applications to feed locations into a location provider so this should not cause any breakage. If a LocationProvider does not fill in enough fields on a Location object then it is dropped, and logged. Bug: 4305998 Change-Id: I7df77125d8a64e174d7bc8c2708661b4f33461ea
This commit is contained in:
@@ -19,6 +19,7 @@ package android.location;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Printer;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
@@ -59,6 +60,7 @@ public class Location implements Parcelable {
|
||||
|
||||
private String mProvider;
|
||||
private long mTime = 0;
|
||||
private long mElapsedRealtimeNano = 0;
|
||||
private double mLatitude = 0.0;
|
||||
private double mLongitude = 0.0;
|
||||
private boolean mHasAltitude = false;
|
||||
@@ -84,6 +86,7 @@ public class Location implements Parcelable {
|
||||
|
||||
public void dump(Printer pw, String prefix) {
|
||||
pw.println(prefix + "mProvider=" + mProvider + " mTime=" + mTime);
|
||||
pw.println(prefix + "mElapsedRealtimeNano=" + mElapsedRealtimeNano);
|
||||
pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
|
||||
pw.println(prefix + "mHasAltitude=" + mHasAltitude + " mAltitude=" + mAltitude);
|
||||
pw.println(prefix + "mHasSpeed=" + mHasSpeed + " mSpeed=" + mSpeed);
|
||||
@@ -118,6 +121,7 @@ public class Location implements Parcelable {
|
||||
public void set(Location l) {
|
||||
mProvider = l.mProvider;
|
||||
mTime = l.mTime;
|
||||
mElapsedRealtimeNano = l.mElapsedRealtimeNano;
|
||||
mLatitude = l.mLatitude;
|
||||
mLongitude = l.mLongitude;
|
||||
mHasAltitude = l.mHasAltitude;
|
||||
@@ -137,6 +141,7 @@ public class Location implements Parcelable {
|
||||
public void reset() {
|
||||
mProvider = null;
|
||||
mTime = 0;
|
||||
mElapsedRealtimeNano = 0;
|
||||
mLatitude = 0;
|
||||
mLongitude = 0;
|
||||
mHasAltitude = false;
|
||||
@@ -467,23 +472,62 @@ public class Location implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UTC time of this fix, in milliseconds since January 1,
|
||||
* Return the UTC time of this fix, in milliseconds since January 1,
|
||||
* 1970.
|
||||
* <p>Note that the UTC time on a device is not monotonic: it
|
||||
* can jump forwards or backwards unpredictably. So always use
|
||||
* {@link #getElapsedRealtimeNano()} when calculating time deltas.
|
||||
* <p>On the other hand, {@link #getTime()} is useful for presenting
|
||||
* a human readable time to the user, or for carefully comparing
|
||||
* location fixes across reboot or across devices.
|
||||
* <p>This method will always return a valid timestamp on
|
||||
* Locations generated by a {@link LocationProvider}.
|
||||
*
|
||||
* @return time of fix, in milliseconds since January 1, 1970.
|
||||
*/
|
||||
public long getTime() {
|
||||
return mTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the UTC time of this fix, in milliseconds since January 1,
|
||||
* Set the UTC time of this fix, in milliseconds since January 1,
|
||||
* 1970.
|
||||
*
|
||||
* @param time UTC time of this fix, in milliseconds since January 1, 1970
|
||||
*/
|
||||
public void setTime(long time) {
|
||||
mTime = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latitude of this fix.
|
||||
* Return the time of this fix, in elapsed real-time since system boot.
|
||||
* <p>This value can be reliably compared to
|
||||
* {@link android.os.SystemClock#elapsedRealtimeNano()},
|
||||
* to calculate the age of a fix, and to compare Location fixes, since
|
||||
* elapsed real-time is guaranteed monotonic for each system boot, and
|
||||
* continues to increment even when the system is in deep sleep.
|
||||
* <p>This method will always return a valid timestamp on
|
||||
* Locations generated by a {@link LocationProvider}.
|
||||
*
|
||||
* @return elapsed real-time of fix, in nanoseconds since system boot.
|
||||
*/
|
||||
public long getElapsedRealtimeNano() {
|
||||
return mElapsedRealtimeNano;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time of this fix, in elapsed real-time since system boot.
|
||||
*
|
||||
* @param time elapsed real-time of fix, in nanoseconds since system boot.
|
||||
*/
|
||||
public void setElapsedRealtimeNano(long time) {
|
||||
mElapsedRealtimeNano = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the latitude of this fix.
|
||||
* <p>This method will always return a valid latitude on
|
||||
* Locations generated by a {@link LocationProvider}.
|
||||
*/
|
||||
public double getLatitude() {
|
||||
return mLatitude;
|
||||
@@ -497,7 +541,9 @@ public class Location implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the longitude of this fix.
|
||||
* Return the longitude of this fix.
|
||||
* <p>This method will always return a valid longitude on
|
||||
* Locations generated by a {@link LocationProvider}.
|
||||
*/
|
||||
public double getLongitude() {
|
||||
return mLongitude;
|
||||
@@ -619,16 +665,27 @@ public class Location implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to report accuracy information,
|
||||
* false otherwise. The default implementation returns false.
|
||||
* Return true if this Location has an associated accuracy.
|
||||
* <p>All Location objects generated by a {@link LocationProvider}
|
||||
* will have an accuracy.
|
||||
*/
|
||||
public boolean hasAccuracy() {
|
||||
return mHasAccuracy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the accuracy of the fix in meters. If hasAccuracy() is false,
|
||||
* 0.0 is returned.
|
||||
* Return the accuracy of this Location fix.
|
||||
* <p>Accuracy is measured in meters, and indicates the
|
||||
* radius of 95% confidence.
|
||||
* In other words, there is a 95% probability that the
|
||||
* true location is within a circle centered at the reported
|
||||
* location, with radius of the reported accuracy.
|
||||
* <p>This is only a measure of horizontal accuracy, and does
|
||||
* not indicate the accuracy of bearing, velocity or altitude
|
||||
* if those are included in this Location.
|
||||
* <p>If {@link #hasAccuracy} is false, 0.0 is returned.
|
||||
* <p>All Location object generated by a {@link LocationProvider}
|
||||
* will have a valid accuracy.
|
||||
*/
|
||||
public float getAccuracy() {
|
||||
return mAccuracy;
|
||||
@@ -652,6 +709,37 @@ public class Location implements Parcelable {
|
||||
mHasAccuracy = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this Location object has enough data set to
|
||||
* be considered a valid fix from a {@link LocationProvider}.
|
||||
* @see #makeComplete
|
||||
* @hide
|
||||
*/
|
||||
public boolean isComplete() {
|
||||
if (mProvider == null) return false;
|
||||
if (!mHasAccuracy) return false;
|
||||
if (mTime == 0) return false;
|
||||
if (mElapsedRealtimeNano == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to fill in incomplete fields.
|
||||
* Only use this to assist in backwards compatibility
|
||||
* with Location objects received from applications.
|
||||
* @see #isComplete
|
||||
* @hide
|
||||
*/
|
||||
public void makeComplete() {
|
||||
if (mProvider == null) mProvider = "?";
|
||||
if (!mHasAccuracy) {
|
||||
mHasAccuracy = true;
|
||||
mAccuracy = 100.0f;
|
||||
}
|
||||
if (mTime == 0) mTime = System.currentTimeMillis();
|
||||
if (mElapsedRealtimeNano == 0) mElapsedRealtimeNano = SystemClock.elapsedRealtimeNano();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional provider-specific information about the
|
||||
* location fix as a Bundle. The keys and values are determined
|
||||
@@ -681,6 +769,7 @@ public class Location implements Parcelable {
|
||||
@Override public String toString() {
|
||||
return "Location[mProvider=" + mProvider +
|
||||
",mTime=" + mTime +
|
||||
",mElapsedRealtimeNano=" + mElapsedRealtimeNano +
|
||||
",mLatitude=" + mLatitude +
|
||||
",mLongitude=" + mLongitude +
|
||||
",mHasAltitude=" + mHasAltitude +
|
||||
@@ -700,6 +789,7 @@ public class Location implements Parcelable {
|
||||
String provider = in.readString();
|
||||
Location l = new Location(provider);
|
||||
l.mTime = in.readLong();
|
||||
l.mElapsedRealtimeNano = in.readLong();
|
||||
l.mLatitude = in.readDouble();
|
||||
l.mLongitude = in.readDouble();
|
||||
l.mHasAltitude = in.readInt() != 0;
|
||||
@@ -726,6 +816,7 @@ public class Location implements Parcelable {
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeString(mProvider);
|
||||
parcel.writeLong(mTime);
|
||||
parcel.writeLong(mElapsedRealtimeNano);
|
||||
parcel.writeDouble(mLatitude);
|
||||
parcel.writeDouble(mLongitude);
|
||||
parcel.writeInt(mHasAltitude ? 1 : 0);
|
||||
|
||||
Reference in New Issue
Block a user