summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordestradaa <destradaa@google.com>2014-06-23 18:19:03 -0700
committerdestradaa <destradaa@google.com>2014-07-11 12:20:39 -0700
commitea8a8a6076f04360de2d25b3e5853cde8026cd5f (patch)
tree7c416b43028165443b11a3e433d9044b54b9fe81
parent34257d8544190979a0c1dfe63350fc50136e4dd0 (diff)
downloadframeworks_base-ea8a8a6076f04360de2d25b3e5853cde8026cd5f.zip
frameworks_base-ea8a8a6076f04360de2d25b3e5853cde8026cd5f.tar.gz
frameworks_base-ea8a8a6076f04360de2d25b3e5853cde8026cd5f.tar.bz2
Update location framework to accept raw data from GPS HAL.
Change-Id: Ib4feca004b53fa89dcece4299974ab08913455a0
-rw-r--r--Android.mk1
-rw-r--r--location/java/android/location/GpsClock.java382
-rw-r--r--location/java/android/location/GpsMeasurement.java1222
-rw-r--r--location/java/android/location/GpsMeasurementListenerTransport.java114
-rw-r--r--location/java/android/location/GpsMeasurementsEvent.aidl19
-rw-r--r--location/java/android/location/GpsMeasurementsEvent.java127
-rw-r--r--location/java/android/location/IGpsMeasurementsListener.aidl26
-rw-r--r--location/java/android/location/ILocationManager.aidl5
-rw-r--r--location/java/android/location/LocationManager.java35
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java74
-rw-r--r--services/core/java/com/android/server/location/GpsLocationProvider.java253
-rw-r--r--services/core/java/com/android/server/location/GpsMeasurementsProvider.java44
-rw-r--r--services/core/java/com/android/server/location/GpsStatusListenerHelper.java91
-rw-r--r--services/core/java/com/android/server/location/RemoteListenerHelper.java148
-rw-r--r--services/core/jni/com_android_server_location_GpsLocationProvider.cpp506
15 files changed, 2835 insertions, 212 deletions
diff --git a/Android.mk b/Android.mk
index 5d957d0..a595d88 100644
--- a/Android.mk
+++ b/Android.mk
@@ -288,6 +288,7 @@ LOCAL_SRC_FILES += \
location/java/android/location/IFusedProvider.aidl \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGeofenceProvider.aidl \
+ location/java/android/location/IGpsMeasurementsListener.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \
diff --git a/location/java/android/location/GpsClock.java b/location/java/android/location/GpsClock.java
new file mode 100644
index 0000000..f327c4e
--- /dev/null
+++ b/location/java/android/location/GpsClock.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 android.location;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class containing a GPS clock timestamp.
+ * It represents a measurement of the GPS receiver's clock.
+ *
+ * @hide
+ */
+public class GpsClock implements Parcelable {
+ // mandatory parameters
+ private long mTimeInNs;
+
+ // optional parameters
+ private boolean mHasLeapSecond;
+ private short mLeapSecond;
+ private boolean mHasTimeUncertaintyInNs;
+ private double mTimeUncertaintyInNs;
+ private boolean mHasBiasInNs;
+ private double mBiasInNs;
+ private boolean mHasBiasUncertaintyInNs;
+ private double mBiasUncertaintyInNs;
+ private boolean mHasDriftInNsPerSec;
+ private double mDriftInNsPerSec;
+ private boolean mHasDriftUncertaintyInNsPerSec;
+ private double mDriftUncertaintyInNsPerSec;
+
+ GpsClock() {
+ reset();
+ }
+
+ /**
+ * Sets all contents to the values stored in the provided object.
+ */
+ public void set(GpsClock clock) {
+ mTimeInNs = clock.mTimeInNs;
+
+ mHasLeapSecond = clock.mHasLeapSecond;
+ mLeapSecond = clock.mLeapSecond;
+ mHasTimeUncertaintyInNs = clock.mHasTimeUncertaintyInNs;
+ mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
+ mHasBiasInNs = clock.mHasBiasInNs;
+ mBiasInNs = clock.mBiasInNs;
+ mHasBiasUncertaintyInNs = clock.mHasBiasUncertaintyInNs;
+ mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
+ mHasDriftInNsPerSec = clock.mHasDriftInNsPerSec;
+ mDriftInNsPerSec = clock.mDriftInNsPerSec;
+ mHasDriftUncertaintyInNsPerSec = clock.mHasDriftUncertaintyInNsPerSec;
+ mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
+ }
+
+ /**
+ * Resets all the contents to its original state.
+ */
+ public void reset() {
+ mTimeInNs = Long.MIN_VALUE;
+
+ resetLeapSecond();
+ resetTimeUncertaintyInNs();
+ resetBiasInNs();
+ resetBiasUncertaintyInNs();
+ resetDriftInNsPerSec();
+ resetDriftUncertaintyInNsPerSec();
+ }
+
+ /**
+ * Returns true if {@link #getLeapSecond()} is available, false otherwise.
+ */
+ public boolean hasLeapSecond() {
+ return mHasLeapSecond;
+ }
+
+ /**
+ * Gets the leap second associated with the clock's time.
+ *
+ * The value is only available if {@link #hasLeapSecond()} is true.
+ */
+ public short getLeapSecond() {
+ return mLeapSecond;
+ }
+
+ /**
+ * Sets the leap second associated with the clock's time.
+ */
+ public void setLeapSecond(short leapSecond) {
+ mHasLeapSecond = true;
+ mLeapSecond = leapSecond;
+ }
+
+ /**
+ * Resets the leap second associated with the clock's time.
+ */
+ public void resetLeapSecond() {
+ mHasLeapSecond = false;
+ mLeapSecond = Short.MIN_VALUE;
+ }
+
+ /**
+ * Gets the GPS clock Time in nanoseconds; it represents the uncorrected receiver's GPS time
+ * since 0000Z, January 6, 1980; this is, including {@link #getBiasInNs()}.
+ * The reported time includes {@link #getTimeUncertaintyInNs()}.
+ */
+ public long getTimeInNs() {
+ return mTimeInNs;
+ }
+
+ /**
+ * Sets the GPS clock Time in nanoseconds.
+ */
+ public void setTimeInNs(long timeInNs) {
+ mTimeInNs = timeInNs;
+ }
+
+ /**
+ * Returns true if {@link #getTimeUncertaintyInNs()} is available, false otherwise.
+ */
+ public boolean hasTimeUncertaintyInNs() {
+ return mHasTimeUncertaintyInNs;
+ }
+
+ /**
+ * Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
+ *
+ * The value is only available if {@link #hasTimeUncertaintyInNs()} is true.
+ */
+ public double getTimeUncertaintyInNs() {
+ return mTimeUncertaintyInNs;
+ }
+
+ /**
+ * Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
+ */
+ public void setTimeUncertaintyInNs(double timeUncertaintyInNs) {
+ mHasTimeUncertaintyInNs = true;
+ mTimeUncertaintyInNs = timeUncertaintyInNs;
+ }
+
+ /**
+ * Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
+ */
+ public void resetTimeUncertaintyInNs() {
+ mHasTimeUncertaintyInNs = false;
+ mTimeUncertaintyInNs = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getBiasInNs()} is available, false otherwise.
+ */
+ public boolean hasBiasInNs() {
+ return mHasBiasInNs;
+ }
+
+ /**
+ * Gets the clock's Bias in nanoseconds.
+ * The sign of the value (if available), is defined by the following equation:
+ * true time = time - bias.
+ * The reported bias includes {@link #getBiasUncertaintyInNs()}.
+ *
+ * The value is only available if {@link #hasBiasInNs()} is true.
+ */
+ public Double getBiasInNs() {
+ return mBiasInNs;
+ }
+
+ /**
+ * Sets the clock's Bias in nanoseconds.
+ */
+ public void setBiasInNs(double biasInNs) {
+ mHasBiasInNs = true;
+ mBiasInNs = biasInNs;
+ }
+
+ /**
+ * Resets the clock's Bias in nanoseconds.
+ */
+ public void resetBiasInNs() {
+ mHasBiasInNs = false;
+ mBiasInNs = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getBiasUncertaintyInNs()} is available, false otherwise.
+ */
+ public boolean hasBiasUncertaintyInNs() {
+ return mHasBiasUncertaintyInNs;
+ }
+
+ /**
+ * Gets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
+ *
+ * The value is only available if {@link #hasBiasUncertaintyInNs()} is true.
+ */
+ public double getBiasUncertaintyInNs() {
+ return mBiasUncertaintyInNs;
+ }
+
+ /**
+ * Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
+ */
+ public void setBiasUncertaintyInNs(double biasUncertaintyInNs) {
+ mHasBiasUncertaintyInNs = true;
+ mBiasUncertaintyInNs = biasUncertaintyInNs;
+ }
+
+ /**
+ * Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
+ */
+ public void resetBiasUncertaintyInNs() {
+ mHasBiasUncertaintyInNs = false;
+ mBiasUncertaintyInNs = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getDriftInNsPerSec()} is available, false otherwise.
+ */
+ public boolean hasDriftInNsPerSec() {
+ return mHasDriftInNsPerSec;
+ }
+
+ /**
+ * Gets the clock's Drift in nanoseconds per second.
+ * A positive value indicates that the frequency is higher than the nominal frequency.
+ * The reported drift includes {@link #getDriftUncertaintyInNsPerSec()}.
+ *
+ * The value is only available if {@link #hasDriftInNsPerSec()} is true.
+ */
+ public double getDriftInNsPerSec() {
+ return mDriftInNsPerSec;
+ }
+
+ /**
+ * Sets the clock's Drift in nanoseconds per second.
+ */
+ public void setDriftInNsPerSec(double driftInNsPerSec) {
+ mHasDriftInNsPerSec = true;
+ mDriftInNsPerSec = driftInNsPerSec;
+ }
+
+ /**
+ * Resets the clock's Drift in nanoseconds per second.
+ */
+ public void resetDriftInNsPerSec() {
+ mHasDriftInNsPerSec = false;
+ mDriftInNsPerSec = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getDriftUncertaintyInNsPerSec()} is available, false otherwise.
+ */
+ public boolean hasDriftUncertaintyInNsPerSec() {
+ return mHasDriftUncertaintyInNsPerSec;
+ }
+
+ /**
+ * Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
+ *
+ * The value is only available if {@link #hasDriftUncertaintyInNsPerSec()} is true.
+ */
+ public double getDriftUncertaintyInNsPerSec() {
+ return mDriftUncertaintyInNsPerSec;
+ }
+
+ /**
+ * Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
+ */
+ public void setDriftUncertaintyInNsPerSec(double driftUncertaintyInNsPerSec) {
+ mHasDriftUncertaintyInNsPerSec = true;
+ mDriftUncertaintyInNsPerSec = driftUncertaintyInNsPerSec;
+ }
+
+ /**
+ * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
+ */
+ public void resetDriftUncertaintyInNsPerSec() {
+ mHasDriftUncertaintyInNsPerSec = false;
+ mDriftUncertaintyInNsPerSec = Double.NaN;
+ }
+
+ public static final Creator<GpsClock> CREATOR = new Creator<GpsClock>() {
+ @Override
+ public GpsClock createFromParcel(Parcel parcel) {
+ GpsClock gpsClock = new GpsClock();
+ gpsClock.mTimeInNs = parcel.readLong();
+
+ gpsClock.mHasLeapSecond = parcel.readInt() != 0;
+ gpsClock.mLeapSecond = (short) parcel.readInt();
+ gpsClock.mHasTimeUncertaintyInNs = parcel.readInt() != 0;
+ gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
+ gpsClock.mHasBiasInNs = parcel.readInt() != 0;
+ gpsClock.mBiasInNs = parcel.readDouble();
+ gpsClock.mHasBiasUncertaintyInNs = parcel.readInt() != 0;
+ gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
+ gpsClock.mHasDriftInNsPerSec = parcel.readInt() != 0;
+ gpsClock.mDriftInNsPerSec = parcel.readDouble();
+ gpsClock.mHasDriftUncertaintyInNsPerSec = parcel.readInt() != 0;
+ gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
+
+ return gpsClock;
+ }
+
+ @Override
+ public GpsClock[] newArray(int size) {
+ return new GpsClock[size];
+ }
+ };
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeLong(mTimeInNs);
+
+ parcel.writeInt(mHasLeapSecond ? 1 : 0);
+ parcel.writeInt(mLeapSecond);
+ parcel.writeInt(mHasTimeUncertaintyInNs ? 1 : 0);
+ parcel.writeDouble(mTimeUncertaintyInNs);
+ parcel.writeInt(mHasBiasInNs ? 1 : 0);
+ parcel.writeDouble(mBiasInNs);
+ parcel.writeInt(mHasBiasUncertaintyInNs ? 1 : 0);
+ parcel.writeDouble(mBiasUncertaintyInNs);
+ parcel.writeInt(mHasDriftInNsPerSec ? 1 : 0);
+ parcel.writeDouble(mDriftInNsPerSec);
+ parcel.writeInt(mHasDriftUncertaintyInNsPerSec ? 1 : 0);
+ parcel.writeDouble(mDriftUncertaintyInNsPerSec);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ final String format = " %-15s = %-25s %-26s = %s\n";
+ StringBuilder builder = new StringBuilder("GpsClock:\n");
+
+ builder.append(String.format(
+ format,
+ "LeapSecond",
+ mHasLeapSecond ? mLeapSecond : null,
+ "",
+ ""));
+
+ builder.append(String.format(
+ format,
+ "TimeInNs",
+ mTimeInNs,
+ "TimeUncertaintyInNs",
+ mHasTimeUncertaintyInNs ? mTimeUncertaintyInNs : null));
+
+ builder.append(String.format(
+ format,
+ "BiasInNs",
+ mHasBiasInNs ? mBiasInNs : null,
+ "BiasUncertaintyInNs",
+ mHasBiasUncertaintyInNs ? mBiasUncertaintyInNs : null));
+
+ builder.append(String.format(
+ format,
+ "DriftInNsPerSec",
+ mHasDriftInNsPerSec ? mDriftInNsPerSec : null,
+ "DriftUncertaintyInNsPerSec",
+ mHasDriftUncertaintyInNsPerSec ? mDriftUncertaintyInNsPerSec : null));
+
+ return builder.toString();
+ }
+}
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
new file mode 100644
index 0000000..e5a8c8c
--- /dev/null
+++ b/location/java/android/location/GpsMeasurement.java
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 android.location;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class representing a GPS satellite measurement, containing raw and computed information.
+ *
+ * @hide
+ */
+public class GpsMeasurement implements Parcelable {
+ private static final String TAG = "GpsMeasurement";
+
+ // mandatory parameters
+ private byte mPrn;
+ private long mLocalTimeInNs;
+ private long mReceivedGpsTowInNs;
+ private double mCn0InDbHz;
+ private double mPseudorangeRateInMetersPerSec;
+ private double mPseudorangeRateUncertaintyInMetersPerSec;
+ private double mAccumulatedDeltaRangeInMeters;
+ private double mAccumulatedDeltaRangeUncertaintyInMeters;
+
+ // optional parameters
+ private boolean mHasPseudorangeInMeters;
+ private double mPseudorangeInMeters;
+ private boolean mHasPseudorangeUncertaintyInMeters;
+ private double mPseudorangeUncertaintyInMeters;
+ private boolean mHasCodePhaseInChips;
+ private double mCodePhaseInChips;
+ private boolean mHasCodePhaseUncertaintyInChips;
+ private double mCodePhaseUncertaintyInChips;
+ private boolean mHasCarrierFrequencyInHz;
+ private float mCarrierFrequencyInHz;
+ private boolean mHasCarrierCycles;
+ private long mCarrierCycles;
+ private boolean mHasCarrierPhase;
+ private double mCarrierPhase;
+ private boolean mHasCarrierPhaseUncertainty;
+ private double mCarrierPhaseUncertainty;
+ private short mLossOfLock;
+ private boolean mHasBitNumber;
+ private short mBitNumber;
+ private boolean mHasTimeFromLastBitInNs;
+ private long mTimeFromLastBitInNs;
+ private boolean mHasDopplerShiftInHz;
+ private double mDopplerShiftInHz;
+ private boolean mHasDopplerShiftUncertaintyInHz;
+ private double mDopplerShiftUncertaintyInHz;
+ private short mMultipathIndicator;
+ private boolean mHasSnrInDb;
+ private double mSnrInDb;
+ private boolean mHasElevationInDeg;
+ private double mElevationInDeg;
+ private boolean mHasElevationUncertaintyInDeg;
+ private double mElevationUncertaintyInDeg;
+ private boolean mHasAzimuthInDeg;
+ private double mAzimuthInDeg;
+ private boolean mHasAzimuthUncertaintyInDeg;
+ private double mAzimuthUncertaintyInDeg;
+ private boolean mUsedInFix;
+
+ // The following enumerations must be in sync with the values declared in gps.h
+
+ /**
+ * The indicator is not available or it is unknown.
+ */
+ public static final short LOSS_OF_LOCK_UNKNOWN = 0;
+
+ /**
+ * The measurement does not present any indication of 'loss of lock'.
+ */
+ public static final short LOSS_OF_LOCK_OK = 1;
+
+ /**
+ * 'Loss of lock' detected between the previous and current observation: cycle slip possible.
+ */
+ public static final short LOSS_OF_LOCK_CYCLE_SLIP = 2;
+
+ /**
+ * The indicator is not available or it is unknown.
+ */
+ public static final short MULTIPATH_INDICATOR_UNKNOWN = 0;
+
+ /**
+ * The measurement has been indicated to use multi-path.
+ */
+ public static final short MULTIPATH_INDICATOR_DETECTED = 1;
+
+ /**
+ * The measurement has been indicated not tu use multi-path.
+ */
+ public static final short MULTIPATH_INDICATOR_NOT_USED = 2;
+
+ // End enumerations in sync with gps.h
+
+ GpsMeasurement() {
+ reset();
+ }
+
+ /**
+ * Sets all contents to the values stored in the provided object.
+ */
+ public void set(GpsMeasurement measurement) {
+ mPrn = measurement.mPrn;
+ mLocalTimeInNs = measurement.mLocalTimeInNs;
+ mReceivedGpsTowInNs = measurement.mReceivedGpsTowInNs;
+ mCn0InDbHz = measurement.mCn0InDbHz;
+ mPseudorangeRateInMetersPerSec = measurement.mPseudorangeRateInMetersPerSec;
+ mPseudorangeRateUncertaintyInMetersPerSec =
+ measurement.mPseudorangeRateUncertaintyInMetersPerSec;
+ mAccumulatedDeltaRangeInMeters = measurement.mAccumulatedDeltaRangeInMeters;
+ mAccumulatedDeltaRangeUncertaintyInMeters =
+ measurement.mAccumulatedDeltaRangeUncertaintyInMeters;
+
+ mHasPseudorangeInMeters = measurement.mHasPseudorangeInMeters;
+ mPseudorangeInMeters = measurement.mPseudorangeInMeters;
+ mHasPseudorangeUncertaintyInMeters = measurement.mHasPseudorangeUncertaintyInMeters;
+ mPseudorangeUncertaintyInMeters = measurement.mPseudorangeUncertaintyInMeters;
+ mHasCodePhaseInChips = measurement.mHasCodePhaseInChips;
+ mCodePhaseInChips = measurement.mCodePhaseInChips;
+ mHasCodePhaseUncertaintyInChips = measurement.mHasCodePhaseUncertaintyInChips;
+ mCodePhaseUncertaintyInChips = measurement.mCodePhaseUncertaintyInChips;
+ mHasCarrierFrequencyInHz = measurement.mHasCarrierFrequencyInHz;
+ mCarrierFrequencyInHz = measurement.mCarrierFrequencyInHz;
+ mHasCarrierCycles = measurement.mHasCarrierCycles;
+ mCarrierCycles = measurement.mCarrierCycles;
+ mHasCarrierPhase = measurement.mHasCarrierPhase;
+ mCarrierPhase = measurement.mCarrierPhase;
+ mHasCarrierPhaseUncertainty = measurement.mHasCarrierPhaseUncertainty;
+ mCarrierPhaseUncertainty = measurement.mCarrierPhaseUncertainty;
+ mLossOfLock = measurement.mLossOfLock;
+ mHasBitNumber = measurement.mHasBitNumber;
+ mBitNumber = measurement.mBitNumber;
+ mHasTimeFromLastBitInNs = measurement.mHasTimeFromLastBitInNs;
+ mTimeFromLastBitInNs = measurement.mTimeFromLastBitInNs;
+ mHasDopplerShiftInHz = measurement.mHasDopplerShiftInHz;
+ mDopplerShiftInHz = measurement.mDopplerShiftInHz;
+ mHasDopplerShiftUncertaintyInHz = measurement.mHasDopplerShiftUncertaintyInHz;
+ mDopplerShiftUncertaintyInHz = measurement.mDopplerShiftUncertaintyInHz;
+ mMultipathIndicator = measurement.mMultipathIndicator;
+ mHasSnrInDb = measurement.mHasSnrInDb;
+ mSnrInDb = measurement.mSnrInDb;
+ mHasElevationInDeg = measurement.mHasElevationInDeg;
+ mElevationInDeg = measurement.mElevationInDeg;
+ mHasElevationUncertaintyInDeg = measurement.mHasElevationUncertaintyInDeg;
+ mElevationUncertaintyInDeg = measurement.mElevationUncertaintyInDeg;
+ mHasAzimuthInDeg = measurement.mHasAzimuthInDeg;
+ mAzimuthInDeg = measurement.mAzimuthInDeg;
+ mHasAzimuthUncertaintyInDeg = measurement.mHasAzimuthUncertaintyInDeg;
+ mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
+ mUsedInFix = measurement.mUsedInFix;
+ }
+
+ /**
+ * Resets all the contents to its original state.
+ */
+ public void reset() {
+ mPrn = Byte.MIN_VALUE;
+ mLocalTimeInNs = Long.MIN_VALUE;
+ mReceivedGpsTowInNs = Long.MIN_VALUE;
+ mCn0InDbHz = Double.MIN_VALUE;
+ mPseudorangeRateInMetersPerSec = Double.MIN_VALUE;
+ mPseudorangeRateUncertaintyInMetersPerSec = Double.MIN_VALUE;
+ mAccumulatedDeltaRangeInMeters = Double.MIN_VALUE;
+ mAccumulatedDeltaRangeUncertaintyInMeters = Double.MIN_VALUE;
+
+ resetPseudorangeInMeters();
+ resetPseudorangeUncertaintyInMeters();
+ resetCodePhaseInChips();
+ resetCodePhaseUncertaintyInChips();
+ resetCarrierFrequencyInHz();
+ resetCarrierCycles();
+ resetCarrierPhase();
+ resetCarrierPhaseUncertainty();
+ setLossOfLock(LOSS_OF_LOCK_UNKNOWN);
+ resetBitNumber();
+ resetTimeFromLastBitInNs();
+ resetDopplerShiftInHz();
+ resetDopplerShiftUncertaintyInHz();
+ setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
+ resetSnrInDb();
+ resetElevationInDeg();
+ resetElevationUncertaintyInDeg();
+ resetAzimuthInDeg();
+ resetAzimuthUncertaintyInDeg();
+ setUsedInFix(false);
+ }
+
+ /**
+ * Gets the Pseudo-random number (PRN).
+ * Range: [1, 32]
+ */
+ public byte getPrn() {
+ return mPrn;
+ }
+
+ /**
+ * Sets the Pseud-random number (PRN).
+ */
+ public void setPrn(byte value) {
+ mPrn = value;
+ }
+
+ /**
+ * Gets the local (hardware) time at which the measurement was taken in nanoseconds.
+ */
+ public long getLocalTimeInNs() {
+ return mLocalTimeInNs;
+ }
+
+ /**
+ * Sets the measurement's local (hardware) time in nanoseconds.
+ */
+ public void setLocalTimeInNs(long value) {
+ mLocalTimeInNs = value;
+ }
+
+ /**
+ * Gets the received GPS Time-of-Week in nanoseconds.
+ * The value is relative to the beginning of the current GPS week.
+ */
+ public long getReceivedGpsTowInNs() {
+ return mReceivedGpsTowInNs;
+ }
+
+ /**
+ * Sets the received GPS time-of-week in nanoseconds.
+ */
+ public void setReceivedGpsTowInNs(long value) {
+ mReceivedGpsTowInNs = value;
+ }
+
+ /**
+ * Gets the Carrier-to-noise density in dB-Hz.
+ * Range: [0, 63].
+ *
+ * The value contains the measured C/N0 for the signal at the antenna input.
+ */
+ public double getCn0InDbHz() {
+ return mCn0InDbHz;
+ }
+
+ /**
+ * Sets the carrier-to-noise density in dB-Hz.
+ */
+ public void setCn0InDbHz(double value) {
+ mCn0InDbHz = value;
+ }
+
+ /**
+ * Gets the Pseudorange rate at the timestamp in m/s.
+ * The reported value includes {@link #getPseudorangeRateUncertaintyInMetersPerSec()}.
+ */
+ public double getPseudorangeRateInMetersPerSec() {
+ return mPseudorangeRateInMetersPerSec;
+ }
+
+ /**
+ * Sets the pseudorange rate at the timestamp in m/s.
+ */
+ public void setPseudorangeRateInMetersPerSec(double value) {
+ mPseudorangeRateInMetersPerSec = value;
+ }
+
+ /**
+ * Gets the pseudorange's rate uncertainty (1-Sigma) in m/s.
+ * The uncertainty is represented as an absolute (single sided) value.
+ */
+ public double getPseudorangeRateUncertaintyInMetersPerSec() {
+ return mPseudorangeRateUncertaintyInMetersPerSec;
+ }
+
+ /**
+ * Sets the pseudorange's rate uncertainty (1-Sigma) in m/s.
+ */
+ public void setPseudorangeRateUncertaintyInMetersPerSec(double value) {
+ mPseudorangeRateUncertaintyInMetersPerSec = value;
+ }
+
+ /**
+ * Gets the accumulated delta range since the last channel reset, in meters.
+ * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyInMeters()}.
+ */
+ public double getAccumulatedDeltaRangeInMeters() {
+ return mAccumulatedDeltaRangeInMeters;
+ }
+
+ /**
+ * Sets the accumulated delta range in meters.
+ */
+ public void setAccumulatedDeltaRangeInMeters(double value) {
+ mAccumulatedDeltaRangeInMeters = value;
+ }
+
+ /**
+ * Gets the accumulated delta range's uncertainty (1-Sigma) in meters.
+ * The uncertainty is represented as an absolute (single sided) value.
+ */
+ public double getAccumulatedDeltaRangeUncertaintyInMeters() {
+ return mAccumulatedDeltaRangeUncertaintyInMeters;
+ }
+
+ /**
+ * Sets the accumulated delta range's uncertainty (1-sigma) in meters.
+ */
+ public void setAccumulatedDeltaRangeUncertaintyInMeters(double value) {
+ mAccumulatedDeltaRangeUncertaintyInMeters = value;
+ }
+
+ /**
+ * Returns true if {@link #getPseudorangeInMeters()} is available, false otherwise.
+ */
+ public boolean hasPseudorangeInMeters() {
+ return mHasPseudorangeInMeters;
+ }
+
+ /**
+ * Gets the best derived pseudorange by the chipset, in meters.
+ * The reported pseudorange includes {@link #getPseudorangeUncertaintyInMeters()}.
+ *
+ * The value is only available if {@link #hasPseudorangeInMeters()} is true.
+ */
+ public double getPseudorangeInMeters() {
+ return mPseudorangeInMeters;
+ }
+
+ /**
+ * Sets the Pseudo-range in meters.
+ */
+ public void setPseudorangeInMeters(double value) {
+ mHasPseudorangeInMeters = true;
+ mPseudorangeInMeters = value;
+ }
+
+ /**
+ * Resets the Pseudo-range in meters.
+ */
+ public void resetPseudorangeInMeters() {
+ mHasPseudorangeInMeters = false;
+ mPseudorangeInMeters = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getPseudorangeUncertaintyInMeters()} is available, false otherwise.
+ */
+ public boolean hasPseudorangeUncertaintyInMeters() {
+ return mHasPseudorangeUncertaintyInMeters;
+ }
+
+ /**
+ * Gets the pseudorange's uncertainty (1-Sigma) in meters.
+ * The value contains the 'pseudorange' and 'clock' uncertainty in it.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * The value is only available if {@link #hasPseudorangeUncertaintyInMeters()} is true.
+ */
+ public double getPseudorangeUncertaintyInMeters() {
+ return mPseudorangeUncertaintyInMeters;
+ }
+
+ /**
+ * Sets the pseudo-range's uncertainty (1-Sigma) in meters.
+ */
+ public void setPseudorangeUncertaintyInMeters(double value) {
+ mHasPseudorangeUncertaintyInMeters = true;
+ mPseudorangeUncertaintyInMeters = value;
+ }
+
+ /**
+ * Resets the pseudo-range's uncertainty (1-Sigma) in meters.
+ */
+ public void resetPseudorangeUncertaintyInMeters() {
+ mHasPseudorangeUncertaintyInMeters = false;
+ mPseudorangeUncertaintyInMeters = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCodePhaseInChips()} is available, false otherwise.
+ */
+ public boolean hasCodePhaseInChips() {
+ return mHasCodePhaseInChips;
+ }
+
+ /**
+ * Gets the fraction of the current C/A code cycle.
+ * Range: [0, 1023]
+ * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+ * The reported code-phase includes {@link #getCodePhaseUncertaintyInChips()}.
+ *
+ * The value is only available if {@link #hasCodePhaseInChips()} is true.
+ */
+ public double getCodePhaseInChips() {
+ return mCodePhaseInChips;
+ }
+
+ /**
+ * Sets the Code-phase in chips.
+ */
+ public void setCodePhaseInChips(double value) {
+ mHasCodePhaseInChips = true;
+ mCodePhaseInChips = value;
+ }
+
+ /**
+ * Resets the Code-phase in chips.
+ */
+ public void resetCodePhaseInChips() {
+ mHasCodePhaseInChips = false;
+ mCodePhaseInChips = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCodePhaseUncertaintyInChips()} is available, false otherwise.
+ */
+ public boolean hasCodePhaseUncertaintyInChips() {
+ return mHasCodePhaseUncertaintyInChips;
+ }
+
+ /**
+ * Gets the code-phase's uncertainty (1-Sigma) as a fraction of chips.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * The value is only available if {@link #hasCodePhaseUncertaintyInChips()} is true.
+ */
+ public double getCodePhaseUncertaintyInChips() {
+ return mCodePhaseUncertaintyInChips;
+ }
+
+ /**
+ * Sets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
+ */
+ public void setCodePhaseUncertaintyInChips(double value) {
+ mHasCodePhaseUncertaintyInChips = true;
+ mCodePhaseUncertaintyInChips = value;
+ }
+
+ /**
+ * Resets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
+ */
+ public void resetCodePhaseUncertaintyInChips() {
+ mHasCodePhaseUncertaintyInChips = false;
+ mCodePhaseUncertaintyInChips = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCarrierFrequencyInHz()} is available, false otherwise.
+ */
+ public boolean hasCarrierFrequencyInHz() {
+ return mHasCarrierFrequencyInHz;
+ }
+
+ /**
+ * Gets the carrier frequency at which codes and messages are modulated, it can be L1 or L2.
+ * If the field is not set, the carrier frequency corresponds to L1.
+ *
+ * The value is only available if {@link #hasCarrierFrequencyInHz()} is true.
+ */
+ public float getCarrierFrequencyInHz() {
+ return mCarrierFrequencyInHz;
+ }
+
+ /**
+ * Sets the Carrier frequency (L1 or L2) in Hz.
+ */
+ public void setCarrierFrequencyInHz(float carrierFrequencyInHz) {
+ mHasCarrierFrequencyInHz = true;
+ mCarrierFrequencyInHz = carrierFrequencyInHz;
+ }
+
+ /**
+ * Resets the Carrier frequency (L1 or L2) in Hz.
+ */
+ public void resetCarrierFrequencyInHz() {
+ mHasCarrierFrequencyInHz = false;
+ mCarrierFrequencyInHz = Float.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCarrierCycles()} is available, false otherwise.
+ */
+ public boolean hasCarrierCycles() {
+ return mHasCarrierCycles;
+ }
+
+ /**
+ * The number of full carrier cycles between the satellite and the receiver.
+ * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+ *
+ * The value is only available if {@link #hasCarrierCycles()} is true.
+ */
+ public long getCarrierCycles() {
+ return mCarrierCycles;
+ }
+
+ /**
+ * Sets the number of full carrier cycles between the satellite and the receiver.
+ */
+ public void setCarrierCycles(long value) {
+ mHasCarrierCycles = true;
+ mCarrierCycles = value;
+ }
+
+ /**
+ * Resets the number of full carrier cycles between the satellite and the receiver.
+ */
+ public void resetCarrierCycles() {
+ mHasCarrierCycles = false;
+ mCarrierCycles = Long.MIN_VALUE;
+ }
+
+ /**
+ * Returns true if {@link #getCarrierPhase()} is available, false otherwise.
+ */
+ public boolean hasCarrierPhase() {
+ return mHasCarrierPhase;
+ }
+
+ /**
+ * Gets the RF phase detected by the receiver.
+ * Range: [0.0, 1.0].
+ * This is usually the fractional part of the complete carrier phase measurement.
+ *
+ * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+ * The reported carrier-phase includes {@link #getCarrierPhaseUncertainty()}.
+ *
+ * The value is only available if {@link #hasCarrierPhase()} is true.
+ */
+ public double getCarrierPhase() {
+ return mCarrierPhase;
+ }
+
+ /**
+ * Sets the RF phase detected by the receiver.
+ */
+ public void setCarrierPhase(double value) {
+ mHasCarrierPhase = true;
+ mCarrierPhase = value;
+ }
+
+ /**
+ * Resets the RF phase detected by the receiver.
+ */
+ public void resetCarrierPhase() {
+ mHasCarrierPhase = false;
+ mCarrierPhase = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCarrierPhaseUncertainty()} is available, false otherwise.
+ */
+ public boolean hasCarrierPhaseUncertainty() {
+ return mHasCarrierPhaseUncertainty;
+ }
+
+ /**
+ * Gets the carrier-phase's uncertainty (1-Sigma).
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * The value is only available if {@link #hasCarrierPhaseUncertainty()} is true.
+ */
+ public double getCarrierPhaseUncertainty() {
+ return mCarrierPhaseUncertainty;
+ }
+
+ /**
+ * Sets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+ */
+ public void setCarrierPhaseUncertainty(double value) {
+ mHasCarrierPhaseUncertainty = true;
+ mCarrierPhaseUncertainty = value;
+ }
+
+ /**
+ * Resets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+ */
+ public void resetCarrierPhaseUncertainty() {
+ mHasCarrierPhaseUncertainty = false;
+ mCarrierPhaseUncertainty = Double.NaN;
+ }
+
+ /**
+ * Gets a value indicating the 'loss of lock' state of the event.
+ */
+ public short getLossOfLock() {
+ return mLossOfLock;
+ }
+
+ /**
+ * Sets the 'loss of lock' status.
+ */
+ public void setLossOfLock(short value) {
+ switch (value) {
+ case LOSS_OF_LOCK_UNKNOWN:
+ case LOSS_OF_LOCK_OK:
+ case LOSS_OF_LOCK_CYCLE_SLIP:
+ mLossOfLock = value;
+ break;
+ default:
+ Log.d(TAG, "Sanitizing invalid 'loss of lock': " + value);
+ mLossOfLock = LOSS_OF_LOCK_UNKNOWN;
+ break;
+ }
+ }
+
+ /**
+ * Gets a string representation of the 'loss of lock'.
+ * For internal and logging use only.
+ */
+ private String getLossOfLockString() {
+ switch (mLossOfLock) {
+ case LOSS_OF_LOCK_UNKNOWN:
+ return "Unknown";
+ case LOSS_OF_LOCK_OK:
+ return "Ok";
+ case LOSS_OF_LOCK_CYCLE_SLIP:
+ return "CycleSlip";
+ default:
+ return "Invalid";
+ }
+ }
+
+ /**
+ * Returns true if {@link #getBitNumber()} is available, false otherwise.
+ */
+ public boolean hasBitNumber() {
+ return mHasBitNumber;
+ }
+
+ /**
+ * Gets the number of GPS bits transmitted since Sat-Sun midnight (GPS week).
+ *
+ * The value is only available if {@link #hasBitNumber()} is true.
+ */
+ public short getBitNumber() {
+ return mBitNumber;
+ }
+
+ /**
+ * Sets the bit number within the broadcast frame.
+ */
+ public void setBitNumber(short bitNumber) {
+ mHasBitNumber = true;
+ mBitNumber = bitNumber;
+ }
+
+ /**
+ * Resets the bit number within the broadcast frame.
+ */
+ public void resetBitNumber() {
+ mHasBitNumber = false;
+ mBitNumber = Short.MIN_VALUE;
+ }
+
+ /**
+ * Returns true if {@link #getTimeFromLastBitInNs()} is available, false otherwise.
+ */
+ public boolean hasTimeFromLastBitInNs() {
+ return mHasTimeFromLastBitInNs;
+ }
+
+ /**
+ * Gets the elapsed time since the last received bit in nanoseconds.
+ * Range: [0, 20000000].
+ *
+ * The value is only available if {@link #hasTimeFromLastBitInNs()} is true.
+ */
+ public long getTimeFromLastBitInNs() {
+ return mTimeFromLastBitInNs;
+ }
+
+ /**
+ * Sets the elapsed time since the last received bit in nanoseconds.
+ */
+ public void setTimeFromLastBitInNs(long value) {
+ mHasTimeFromLastBitInNs = true;
+ mTimeFromLastBitInNs = value;
+ }
+
+ /**
+ * Resets the elapsed time since the last received bit in nanoseconds.
+ */
+ public void resetTimeFromLastBitInNs() {
+ mHasTimeFromLastBitInNs = false;
+ mTimeFromLastBitInNs = Long.MIN_VALUE;
+ }
+
+ /**
+ * Returns true if {@link #getDopplerShiftInHz()} is available, false otherwise.
+ */
+ public boolean hasDopplerShiftInHz() {
+ return mHasDopplerShiftInHz;
+ }
+
+ /**
+ * Gets the Doppler Shift in Hz.
+ * A positive value indicates that the SV is moving toward the receiver.
+ *
+ * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+ * The reported doppler shift includes {@link #getDopplerShiftUncertaintyInHz()}.
+ *
+ * The value is only available if {@link #hasDopplerShiftInHz()} is true.
+ */
+ public double getDopplerShiftInHz() {
+ return mDopplerShiftInHz;
+ }
+
+ /**
+ * Sets the Doppler shift in Hz.
+ */
+ public void setDopplerShiftInHz(double value) {
+ mHasDopplerShiftInHz = true;
+ mDopplerShiftInHz = value;
+ }
+
+ /**
+ * Resets the Doppler shift in Hz.
+ */
+ public void resetDopplerShiftInHz() {
+ mHasDopplerShiftInHz = false;
+ mDopplerShiftInHz = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getDopplerShiftUncertaintyInHz()} is available, false otherwise.
+ */
+ public boolean hasDopplerShiftUncertaintyInHz() {
+ return mHasDopplerShiftUncertaintyInHz;
+ }
+
+ /**
+ * Gets the Doppler's Shift uncertainty (1-Sigma) in Hz.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * The value is only available if {@link #hasDopplerShiftUncertaintyInHz()} is true.
+ */
+ public double getDopplerShiftUncertaintyInHz() {
+ return mDopplerShiftUncertaintyInHz;
+ }
+
+ /**
+ * Sets the Doppler's shift uncertainty (1-Sigma) in Hz.
+ */
+ public void setDopplerShiftUncertaintyInHz(double value) {
+ mHasDopplerShiftUncertaintyInHz = true;
+ mDopplerShiftUncertaintyInHz = value;
+ }
+
+ /**
+ * Resets the Doppler's shift uncertainty (1-Sigma) in Hz.
+ */
+ public void resetDopplerShiftUncertaintyInHz() {
+ mHasDopplerShiftUncertaintyInHz = false;
+ mDopplerShiftUncertaintyInHz = Double.NaN;
+ }
+
+ /**
+ * Gets a value indicating the 'multipath' state of the event.
+ */
+ public short getMultipathIndicator() {
+ return mMultipathIndicator;
+ }
+
+ /**
+ * Sets the 'multi-path' indicator.
+ */
+ public void setMultipathIndicator(short value) {
+ switch (value) {
+ case MULTIPATH_INDICATOR_UNKNOWN:
+ case MULTIPATH_INDICATOR_DETECTED:
+ case MULTIPATH_INDICATOR_NOT_USED:
+ mMultipathIndicator = value;
+ break;
+ default:
+ Log.d(TAG, "Sanitizing invalid 'muti-path indicator': " + value);
+ mMultipathIndicator = MULTIPATH_INDICATOR_UNKNOWN;
+ break;
+ }
+ }
+
+ /**
+ * Gets a string representation of the 'multi-path indicator'.
+ * For internal and logging use only.
+ */
+ private String getMultipathIndicatorString() {
+ switch(mMultipathIndicator) {
+ case MULTIPATH_INDICATOR_UNKNOWN:
+ return "Unknown";
+ case MULTIPATH_INDICATOR_DETECTED:
+ return "Detected";
+ case MULTIPATH_INDICATOR_NOT_USED:
+ return "NotDetected";
+ default:
+ return "Invalid";
+ }
+ }
+
+ /**
+ * Returns true if {@link #getSnrInDb()} is available, false otherwise.
+ */
+ public boolean hasSnrInDb() {
+ return mHasSnrInDb;
+ }
+
+ /**
+ * Gets the Signal-to-Noise ratio (SNR) in dB.
+ *
+ * The value is only available if {@link #hasSnrInDb()} is true.
+ */
+ public double getSnrInDb() {
+ return mSnrInDb;
+ }
+
+ /**
+ * Sets the Signal-to-noise ratio (SNR) in dB.
+ */
+ public void setSnrInDb(double snrInDb) {
+ mHasSnrInDb = true;
+ mSnrInDb = snrInDb;
+ }
+
+ /**
+ * Resets the Signal-to-noise ratio (SNR) in dB.
+ */
+ public void resetSnrInDb() {
+ mHasSnrInDb = false;
+ mSnrInDb = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getElevationInDeg()} is available, false otherwise.
+ */
+ public boolean hasElevationInDeg() {
+ return mHasElevationInDeg;
+ }
+
+ /**
+ * Gets the Elevation in degrees.
+ * Range: [-90, 90]
+ * The reported elevation includes {@link #getElevationUncertaintyInDeg()}.
+ *
+ * The value is only available if {@link #hasElevationInDeg()} is true.
+ */
+ public double getElevationInDeg() {
+ return mElevationInDeg;
+ }
+
+ /**
+ * Sets the Elevation in degrees.
+ */
+ public void setElevationInDeg(double elevationInDeg) {
+ mHasElevationInDeg = true;
+ mElevationInDeg = elevationInDeg;
+ }
+
+ /**
+ * Resets the Elevation in degrees.
+ */
+ public void resetElevationInDeg() {
+ mHasElevationInDeg = false;
+ mElevationInDeg = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getElevationUncertaintyInDeg()} is available, false otherwise.
+ */
+ public boolean hasElevationUncertaintyInDeg() {
+ return mHasElevationUncertaintyInDeg;
+ }
+
+ /**
+ * Gets the elevation's uncertainty (1-Sigma) in degrees.
+ * Range: [0, 90]
+ *
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * The value is only available if {@link #hasElevationUncertaintyInDeg()} is true.
+ */
+ public double getElevationUncertaintyInDeg() {
+ return mElevationUncertaintyInDeg;
+ }
+
+ /**
+ * Sets the elevation's uncertainty (1-Sigma) in degrees.
+ */
+ public void setElevationUncertaintyInDeg(double value) {
+ mHasElevationUncertaintyInDeg = true;
+ mElevationUncertaintyInDeg = value;
+ }
+
+ /**
+ * Resets the elevation's uncertainty (1-Sigma) in degrees.
+ */
+ public void resetElevationUncertaintyInDeg() {
+ mHasElevationUncertaintyInDeg = false;
+ mElevationUncertaintyInDeg = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getAzimuthInDeg()} is available, false otherwise.
+ */
+ public boolean hasAzimuthInDeg() {
+ return mHasAzimuthInDeg;
+ }
+
+ /**
+ * Gets the azimuth in degrees.
+ * Range: [0, 360).
+ *
+ * The reported azimuth includes {@link #getAzimuthUncertaintyInDeg()}.
+ *
+ * The value is only available if {@link #hasAzimuthInDeg()} is true.
+ */
+ public double getAzimuthInDeg() {
+ return mAzimuthInDeg;
+ }
+
+ /**
+ * Sets the Azimuth in degrees.
+ */
+ public void setAzimuthInDeg(double value) {
+ mHasAzimuthInDeg = true;
+ mAzimuthInDeg = value;
+ }
+
+ /**
+ * Resets the Azimuth in degrees.
+ */
+ public void resetAzimuthInDeg() {
+ mHasAzimuthInDeg = false;
+ mAzimuthInDeg = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getAzimuthUncertaintyInDeg()} is available, false otherwise.
+ */
+ public boolean hasAzimuthUncertaintyInDeg() {
+ return mHasAzimuthUncertaintyInDeg;
+ }
+
+ /**
+ * Gets the azimuth's uncertainty (1-Sigma) in degrees.
+ * Range: [0, 180].
+ *
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * The value is only available if {@link #hasAzimuthUncertaintyInDeg()} is true.
+ */
+ public double getAzimuthUncertaintyInDeg() {
+ return mAzimuthUncertaintyInDeg;
+ }
+
+ /**
+ * Sets the Azimuth's uncertainty (1-Sigma) in degrees.
+ */
+ public void setAzimuthUncertaintyInDeg(double value) {
+ mHasAzimuthUncertaintyInDeg = true;
+ mAzimuthUncertaintyInDeg = value;
+ }
+
+ /**
+ * Resets the Azimuth's uncertainty (1-Sigma) in degrees.
+ */
+ public void resetAzimuthUncertaintyInDeg() {
+ mHasAzimuthUncertaintyInDeg = false;
+ mAzimuthUncertaintyInDeg = Double.NaN;
+ }
+
+ /**
+ * Gets a flag indicating whether the GPS represented by the measurement was used for computing
+ * the most recent fix.
+ *
+ * @return A non-null value if the data is available, null otherwise.
+ */
+ public Boolean isUsedInFix() {
+ return mUsedInFix;
+ }
+
+ /**
+ * Sets the Used-in-Fix flag.
+ */
+ public void setUsedInFix(boolean value) {
+ mUsedInFix = value;
+ }
+
+ public static final Creator<GpsMeasurement> CREATOR = new Creator<GpsMeasurement>() {
+ @Override
+ public GpsMeasurement createFromParcel(Parcel parcel) {
+ GpsMeasurement gpsMeasurement = new GpsMeasurement();
+
+ gpsMeasurement.mPrn = parcel.readByte();
+ gpsMeasurement.mLocalTimeInNs = parcel.readLong();
+ gpsMeasurement.mReceivedGpsTowInNs = parcel.readLong();
+ gpsMeasurement.mCn0InDbHz = parcel.readDouble();
+ gpsMeasurement.mPseudorangeRateInMetersPerSec = parcel.readDouble();
+ gpsMeasurement.mPseudorangeRateUncertaintyInMetersPerSec = parcel.readDouble();
+ gpsMeasurement.mAccumulatedDeltaRangeInMeters = parcel.readDouble();
+ gpsMeasurement.mAccumulatedDeltaRangeUncertaintyInMeters = parcel.readDouble();
+
+ gpsMeasurement.mHasPseudorangeInMeters = parcel.readInt() != 0;
+ gpsMeasurement.mPseudorangeInMeters = parcel.readDouble();
+ gpsMeasurement.mHasPseudorangeUncertaintyInMeters = parcel.readInt() != 0;
+ gpsMeasurement.mPseudorangeUncertaintyInMeters = parcel.readDouble();
+ gpsMeasurement.mHasCodePhaseInChips = parcel.readInt() != 0;
+ gpsMeasurement.mCodePhaseInChips = parcel.readDouble();
+ gpsMeasurement.mHasCodePhaseUncertaintyInChips = parcel.readInt() != 0;
+ gpsMeasurement.mCodePhaseUncertaintyInChips = parcel.readDouble();
+ gpsMeasurement.mHasCarrierFrequencyInHz = parcel.readInt() != 0;
+ gpsMeasurement.mCarrierFrequencyInHz = parcel.readFloat();
+ gpsMeasurement.mHasCarrierCycles = parcel.readInt() != 0;
+ gpsMeasurement.mCarrierCycles = parcel.readLong();
+ gpsMeasurement.mHasCarrierPhase = parcel.readInt() != 0;
+ gpsMeasurement.mCarrierPhase = parcel.readDouble();
+ gpsMeasurement.mHasCarrierPhaseUncertainty = parcel.readInt() != 0;
+ gpsMeasurement.mCarrierPhaseUncertainty = parcel.readDouble();
+ gpsMeasurement.mLossOfLock = (short) parcel.readInt();
+ gpsMeasurement.mHasBitNumber = parcel.readInt() != 0;
+ gpsMeasurement.mBitNumber = (short) parcel.readInt();
+ gpsMeasurement.mHasTimeFromLastBitInNs = parcel.readInt() != 0;
+ gpsMeasurement.mTimeFromLastBitInNs = parcel.readLong();
+ gpsMeasurement.mHasDopplerShiftInHz = parcel.readInt() != 0;
+ gpsMeasurement.mDopplerShiftInHz = parcel.readDouble();
+ gpsMeasurement.mHasDopplerShiftUncertaintyInHz = parcel.readInt() != 0;
+ gpsMeasurement.mDopplerShiftUncertaintyInHz = parcel.readDouble();
+ gpsMeasurement.mMultipathIndicator = (short) parcel.readInt();
+ gpsMeasurement.mHasSnrInDb = parcel.readInt() != 0;
+ gpsMeasurement.mSnrInDb = parcel.readDouble();
+ gpsMeasurement.mHasElevationInDeg = parcel.readInt() != 0;
+ gpsMeasurement.mElevationInDeg = parcel.readDouble();
+ gpsMeasurement.mHasElevationUncertaintyInDeg = parcel.readInt() != 0;
+ gpsMeasurement.mElevationUncertaintyInDeg = parcel.readDouble();
+ gpsMeasurement.mHasAzimuthInDeg = parcel.readInt() != 0;
+ gpsMeasurement.mAzimuthInDeg = parcel.readDouble();
+ gpsMeasurement.mHasAzimuthUncertaintyInDeg = parcel.readInt() != 0;
+ gpsMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
+ gpsMeasurement.mUsedInFix = parcel.readInt() != 0;
+
+ return gpsMeasurement;
+ }
+
+ @Override
+ public GpsMeasurement[] newArray(int i) {
+ return new GpsMeasurement[i];
+ }
+ };
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeByte(mPrn);
+ parcel.writeLong(mLocalTimeInNs);
+ parcel.writeLong(mReceivedGpsTowInNs);
+ parcel.writeDouble(mCn0InDbHz);
+ parcel.writeDouble(mPseudorangeRateInMetersPerSec);
+ parcel.writeDouble(mPseudorangeRateUncertaintyInMetersPerSec);
+ parcel.writeDouble(mAccumulatedDeltaRangeInMeters);
+ parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyInMeters);
+
+ parcel.writeInt(mHasPseudorangeInMeters ? 1 : 0);
+ parcel.writeDouble(mPseudorangeInMeters);
+ parcel.writeInt(mHasPseudorangeUncertaintyInMeters ? 1 : 0);
+ parcel.writeDouble(mPseudorangeUncertaintyInMeters);
+ parcel.writeInt(mHasCodePhaseInChips ? 1 : 0);
+ parcel.writeDouble(mCodePhaseInChips);
+ parcel.writeInt(mHasCodePhaseUncertaintyInChips ? 1 : 0);
+ parcel.writeDouble(mCodePhaseUncertaintyInChips);
+ parcel.writeInt(mHasCarrierFrequencyInHz ? 1 : 0);
+ parcel.writeFloat(mCarrierFrequencyInHz);
+ parcel.writeInt(mHasCarrierCycles ? 1 : 0);
+ parcel.writeLong(mCarrierCycles);
+ parcel.writeInt(mHasCarrierPhase ? 1 : 0);
+ parcel.writeDouble(mCarrierPhase);
+ parcel.writeInt(mHasCarrierPhaseUncertainty ? 1 : 0);
+ parcel.writeDouble(mCarrierPhaseUncertainty);
+ parcel.writeInt(mLossOfLock);
+ parcel.writeInt(mHasBitNumber ? 1 : 0);
+ parcel.writeInt(mBitNumber);
+ parcel.writeInt(mHasTimeFromLastBitInNs ? 1 : 0);
+ parcel.writeLong(mTimeFromLastBitInNs);
+ parcel.writeInt(mHasDopplerShiftInHz ? 1 : 0);
+ parcel.writeDouble(mDopplerShiftInHz);
+ parcel.writeInt(mHasDopplerShiftUncertaintyInHz ? 1 : 0);
+ parcel.writeDouble(mDopplerShiftUncertaintyInHz);
+ parcel.writeInt(mMultipathIndicator);
+ parcel.writeInt(mHasSnrInDb ? 1 : 0);
+ parcel.writeDouble(mSnrInDb);
+ parcel.writeInt(mHasElevationInDeg ? 1 : 0);
+ parcel.writeDouble(mElevationInDeg);
+ parcel.writeInt(mHasElevationUncertaintyInDeg ? 1 : 0);
+ parcel.writeDouble(mElevationUncertaintyInDeg);
+ parcel.writeInt(mHasAzimuthInDeg ? 1 : 0);
+ parcel.writeDouble(mAzimuthInDeg);
+ parcel.writeInt(mHasAzimuthUncertaintyInDeg ? 1 : 0);
+ parcel.writeDouble(mAzimuthUncertaintyInDeg);
+ parcel.writeInt(mUsedInFix ? 1 : 0);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ final String format = " %-29s = %s\n";
+ final String formatWithUncertainty = " %-29s = %-25s %-40s = %s\n";
+ StringBuilder builder = new StringBuilder("GpsMeasurement:\n");
+
+ builder.append(String.format(format, "Prn", mPrn));
+
+ builder.append(String.format(format, "LocalTimeInNs", mLocalTimeInNs));
+
+ builder.append(String.format(format, "ReceivedGpsTowInNs", mReceivedGpsTowInNs));
+
+ builder.append(String.format(format, "Cn0InDbHz", mCn0InDbHz));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "PseudorangeRateInMetersPerSec",
+ mPseudorangeRateInMetersPerSec,
+ "PseudorangeRateUncertaintyInMetersPerSec",
+ mPseudorangeRateUncertaintyInMetersPerSec));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "AccumulatedDeltaRangeInMeters",
+ mAccumulatedDeltaRangeInMeters,
+ "AccumulatedDeltaRangeUncertaintyInMeters",
+ mAccumulatedDeltaRangeUncertaintyInMeters));
+
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "PseudorangeInMeters",
+ mHasPseudorangeInMeters ? mPseudorangeInMeters : null,
+ "PseudorangeUncertaintyInMeters",
+ mHasPseudorangeUncertaintyInMeters ? mPseudorangeUncertaintyInMeters : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "CodePhaseInChips",
+ mHasCodePhaseInChips ? mCodePhaseInChips : null,
+ "CodePhaseUncertaintyInChips",
+ mHasCodePhaseUncertaintyInChips ? mCodePhaseUncertaintyInChips : null));
+
+ builder.append(String.format(
+ format,
+ "CarrierFrequencyInHz",
+ mHasCarrierFrequencyInHz ? mCarrierFrequencyInHz : null));
+
+ builder.append(String.format(
+ format,
+ "CarrierCycles",
+ mHasCarrierCycles ? mCarrierCycles : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "CarrierPhase",
+ mHasCarrierPhase ? mCarrierPhase : null,
+ "CarrierPhaseUncertainty",
+ mHasCarrierPhaseUncertainty ? mCarrierPhaseUncertainty : null));
+
+ builder.append(String.format(format, "LossOfLock", getLossOfLockString()));
+
+ builder.append(String.format(
+ format,
+ "BitNumber",
+ mHasBitNumber ? mBitNumber : null));
+
+ builder.append(String.format(
+ format,
+ "TimeFromLastBitInNs",
+ mHasTimeFromLastBitInNs ? mTimeFromLastBitInNs : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "DopplerShiftInHz",
+ mHasDopplerShiftInHz ? mDopplerShiftInHz : null,
+ "DopplerShiftUncertaintyInHz",
+ mHasDopplerShiftUncertaintyInHz ? mDopplerShiftUncertaintyInHz : null));
+
+ builder.append(String.format(format, "MultipathIndicator", getMultipathIndicatorString()));
+
+ builder.append(String.format(
+ format,
+ "SnrInDb",
+ mHasSnrInDb ? mSnrInDb : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "ElevationInDeg",
+ mHasElevationInDeg ? mElevationInDeg : null,
+ "ElevationUncertaintyInDeg",
+ mHasElevationUncertaintyInDeg ? mElevationUncertaintyInDeg : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "AzimuthInDeg",
+ mHasAzimuthInDeg ? mAzimuthInDeg : null,
+ "AzimuthUncertaintyInDeg",
+ mHasAzimuthUncertaintyInDeg ? mAzimuthUncertaintyInDeg : null));
+
+ builder.append(String.format(format, "UsedInFix", mUsedInFix));
+
+ return builder.toString();
+ }
+}
diff --git a/location/java/android/location/GpsMeasurementListenerTransport.java b/location/java/android/location/GpsMeasurementListenerTransport.java
new file mode 100644
index 0000000..48a4b44
--- /dev/null
+++ b/location/java/android/location/GpsMeasurementListenerTransport.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 android.location;
+
+import com.android.internal.util.Preconditions;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener},
+ * and post the events in a handler.
+ *
+ * @hide
+ */
+class GpsMeasurementListenerTransport {
+ private static final String TAG = "GpsMeasurementListenerTransport";
+
+ private final Context mContext;
+ private final ILocationManager mLocationManager;
+
+ private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
+ private final HashSet<GpsMeasurementsEvent.Listener> mListeners =
+ new HashSet<GpsMeasurementsEvent.Listener>();
+
+ public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) {
+ mContext = context;
+ mLocationManager = locationManager;
+ }
+
+ public boolean add(@NonNull GpsMeasurementsEvent.Listener listener) {
+ Preconditions.checkNotNull(listener);
+
+ synchronized (mListeners) {
+ // we need to register with the service first, because we need to find out if the
+ // service will actually support the request before we attempt anything
+ if (mListeners.isEmpty()) {
+ boolean registeredWithServer;
+ try {
+ registeredWithServer = mLocationManager.addGpsMeasurementsListener(
+ mListenerTransport,
+ mContext.getPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error handling first listener.", e);
+ return false;
+ }
+
+ if (!registeredWithServer) {
+ Log.e(TAG, "Unable to register listener transport.");
+ return false;
+ }
+ }
+
+ if (mListeners.contains(listener)) {
+ return true;
+ }
+
+ mListeners.add(listener);
+ }
+
+ return true;
+ }
+
+ public void remove(@NonNull GpsMeasurementsEvent.Listener listener) {
+ Preconditions.checkNotNull(listener);
+
+ synchronized (mListeners) {
+ boolean removed = mListeners.remove(listener);
+
+ boolean isLastListener = removed && mListeners.isEmpty();
+ if (isLastListener) {
+ try {
+ mLocationManager.removeGpsMeasurementsListener(mListenerTransport);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error handling last listener.", e);
+ }
+ }
+ }
+ }
+
+ private class ListenerTransport extends IGpsMeasurementsListener.Stub {
+ @Override
+ public void onGpsMeasurementsReceived(final GpsMeasurementsEvent eventArgs) {
+ Collection<GpsMeasurementsEvent.Listener> listeners;
+ synchronized (mListeners) {
+ listeners = new ArrayList<GpsMeasurementsEvent.Listener>(mListeners);
+ }
+
+ for (final GpsMeasurementsEvent.Listener listener : listeners) {
+ listener.onGpsMeasurementsReceived(eventArgs);
+ }
+ }
+ }
+}
diff --git a/location/java/android/location/GpsMeasurementsEvent.aidl b/location/java/android/location/GpsMeasurementsEvent.aidl
new file mode 100644
index 0000000..2c46262
--- /dev/null
+++ b/location/java/android/location/GpsMeasurementsEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014, The Android Open Source Project
+ *
+ * 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 android.location;
+
+parcelable GpsMeasurementsEvent;
diff --git a/location/java/android/location/GpsMeasurementsEvent.java b/location/java/android/location/GpsMeasurementsEvent.java
new file mode 100644
index 0000000..e04ed81
--- /dev/null
+++ b/location/java/android/location/GpsMeasurementsEvent.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 android.location;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.security.InvalidParameterException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * A class implementing a container for data associated with a measurement event.
+ * Events are delivered to registered instances of {@link Listener}.
+ *
+ * @hide
+ */
+public class GpsMeasurementsEvent implements Parcelable {
+ private final GpsClock mClock;
+ private final Collection<GpsMeasurement> mReadOnlyMeasurements;
+
+ /**
+ * Used for receiving GPS satellite measurements from the GPS engine.
+ * Each measurement contains raw and computed data identifying a satellite.
+ * You can implement this interface and call {@link LocationManager#addGpsMeasurementListener}.
+ *
+ * @hide
+ */
+ public interface Listener {
+ void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs);
+ }
+
+ public GpsMeasurementsEvent(GpsClock clock, GpsMeasurement[] measurements) {
+ if (clock == null) {
+ throw new InvalidParameterException("Parameter 'clock' must not be null.");
+ }
+ if (measurements == null || measurements.length == 0) {
+ throw new InvalidParameterException(
+ "Parameter 'measurements' must not be null or empty.");
+ }
+
+ mClock = clock;
+ Collection<GpsMeasurement> measurementCollection = Arrays.asList(measurements);
+ mReadOnlyMeasurements = Collections.unmodifiableCollection(measurementCollection);
+ }
+
+ @NonNull
+ public GpsClock getClock() {
+ return mClock;
+ }
+
+ /**
+ * Gets a read-only collection of measurements associated with the current event.
+ */
+ @NonNull
+ public Collection<GpsMeasurement> getMeasurements() {
+ return mReadOnlyMeasurements;
+ }
+
+ public static final Creator<GpsMeasurementsEvent> CREATOR =
+ new Creator<GpsMeasurementsEvent>() {
+ @Override
+ public GpsMeasurementsEvent createFromParcel(Parcel in) {
+ ClassLoader classLoader = getClass().getClassLoader();
+
+ GpsClock clock = in.readParcelable(classLoader);
+
+ int measurementsLength = in.readInt();
+ GpsMeasurement[] measurementsArray = new GpsMeasurement[measurementsLength];
+ in.readTypedArray(measurementsArray, GpsMeasurement.CREATOR);
+
+ return new GpsMeasurementsEvent(clock, measurementsArray);
+ }
+
+ @Override
+ public GpsMeasurementsEvent[] newArray(int size) {
+ return new GpsMeasurementsEvent[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mClock, flags);
+
+ GpsMeasurement[] measurementsArray = mReadOnlyMeasurements.toArray(new GpsMeasurement[0]);
+ parcel.writeInt(measurementsArray.length);
+ parcel.writeTypedArray(measurementsArray, flags);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("[ GpsMeasurementsEvent:\n\n");
+
+ builder.append(mClock.toString());
+ builder.append("\n");
+
+ for (GpsMeasurement measurement : mReadOnlyMeasurements) {
+ builder.append(measurement.toString());
+ builder.append("\n");
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+}
diff --git a/location/java/android/location/IGpsMeasurementsListener.aidl b/location/java/android/location/IGpsMeasurementsListener.aidl
new file mode 100644
index 0000000..b34bb6c
--- /dev/null
+++ b/location/java/android/location/IGpsMeasurementsListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014, The Android Open Source Project
+ *
+ * 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 android.location;
+
+import android.location.GpsMeasurementsEvent;
+
+/**
+ * {@hide}
+ */
+oneway interface IGpsMeasurementsListener {
+ void onGpsMeasurementsReceived(in GpsMeasurementsEvent event);
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index c353ec6..a1acaf1 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -21,7 +21,7 @@ import android.location.Address;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
-import android.location.IGeocodeProvider;
+import android.location.IGpsMeasurementsListener;
import android.location.IGpsStatusListener;
import android.location.ILocationListener;
import android.location.Location;
@@ -60,6 +60,9 @@ interface ILocationManager
boolean sendNiResponse(int notifId, int userResponse);
+ boolean addGpsMeasurementsListener(in IGpsMeasurementsListener listener, in String packageName);
+ boolean removeGpsMeasurementsListener(in IGpsMeasurementsListener listener);
+
// --- deprecated ---
List<String> getAllProviders();
List<String> getProviders(in Criteria criteria, boolean enabledOnly);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 4502a5b..d6a8fb8 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -16,25 +16,23 @@
package android.location;
+import com.android.internal.location.ProviderProperties;
+
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
-import android.os.Looper;
-import android.os.RemoteException;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.util.Log;
-
-import java.lang.SecurityException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import com.android.internal.location.ProviderProperties;
-
/**
* This class provides access to the system location services. These
* services allow applications to obtain periodic updates of the
@@ -60,6 +58,7 @@ public class LocationManager {
private final Context mContext;
private final ILocationManager mService;
+ private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport;
private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
@@ -310,6 +309,7 @@ public class LocationManager {
public LocationManager(Context context, ILocationManager service) {
mService = service;
mContext = context;
+ mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService);
}
private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1570,6 +1570,29 @@ public class LocationManager {
}
}
+ /**
+ * Adds a GPS Measurement listener.
+ *
+ * @param listener a {@link android.location.GpsMeasurementsEvent.Listener} object to register.
+ * @return {@code true} if the listener was successfully registered, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
+ return mGpsMeasurementListenerTransport.add(listener);
+ }
+
+ /**
+ * Removes a GPS Measurement listener.
+ *
+ * @param listener a {@link GpsMeasurementsEvent.Listener} object to remove.
+ *
+ * @hide
+ */
+ public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
+ mGpsMeasurementListenerTransport.remove(listener);
+ }
+
/**
* Retrieves information about the current status of the GPS engine.
* This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 10382ba..67e58a6 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -16,6 +16,27 @@
package com.android.server;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.location.FlpHardwareProvider;
+import com.android.server.location.FusedProxy;
+import com.android.server.location.GeocoderProxy;
+import com.android.server.location.GeofenceManager;
+import com.android.server.location.GeofenceProxy;
+import com.android.server.location.GpsLocationProvider;
+import com.android.server.location.GpsMeasurementsProvider;
+import com.android.server.location.LocationBlacklist;
+import com.android.server.location.LocationFudger;
+import com.android.server.location.LocationProviderInterface;
+import com.android.server.location.LocationProviderProxy;
+import com.android.server.location.LocationRequestStatistics;
+import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
+import com.android.server.location.LocationRequestStatistics.PackageStatistics;
+import com.android.server.location.MockProvider;
+import com.android.server.location.PassiveProvider;
+
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -36,6 +57,7 @@ import android.location.Address;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
+import android.location.IGpsMeasurementsListener;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
@@ -62,26 +84,6 @@ import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-import com.android.internal.os.BackgroundThread;
-import com.android.server.location.FlpHardwareProvider;
-import com.android.server.location.FusedProxy;
-import com.android.server.location.GeocoderProxy;
-import com.android.server.location.GeofenceProxy;
-import com.android.server.location.GeofenceManager;
-import com.android.server.location.GpsLocationProvider;
-import com.android.server.location.LocationBlacklist;
-import com.android.server.location.LocationFudger;
-import com.android.server.location.LocationProviderInterface;
-import com.android.server.location.LocationProviderProxy;
-import com.android.server.location.LocationRequestStatistics;
-import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
-import com.android.server.location.LocationRequestStatistics.PackageStatistics;
-import com.android.server.location.MockProvider;
-import com.android.server.location.PassiveProvider;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -154,6 +156,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private LocationWorkerHandler mLocationHandler;
private PassiveProvider mPassiveProvider; // track passive provider for special cases
private LocationBlacklist mBlacklist;
+ private GpsMeasurementsProvider mGpsMeasurementsProvider;
// --- fields below are protected by mLock ---
// Set of providers that are explicitly enabled
@@ -403,6 +406,7 @@ public class LocationManagerService extends ILocationManager.Stub {
addProviderLocked(gpsProvider);
mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
}
+ mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
/*
Load package name(s) containing location provider support.
@@ -1804,6 +1808,36 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
+ public boolean addGpsMeasurementsListener(
+ IGpsMeasurementsListener listener,
+ String packageName) {
+ int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+ checkResolutionLevelIsSufficientForProviderUse(
+ allowedResolutionLevel,
+ LocationManager.GPS_PROVIDER);
+
+ int uid = Binder.getCallingUid();
+ long identity = Binder.clearCallingIdentity();
+ boolean hasLocationAccess;
+ try {
+ hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ if (!hasLocationAccess) {
+ return false;
+ }
+
+ return mGpsMeasurementsProvider.addListener(listener);
+ }
+
+ @Override
+ public boolean removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
+ return mGpsMeasurementsProvider.removeListener(listener);
+ }
+
+ @Override
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
if (provider == null) {
// throw NullPointerException to remain compatible with previous implementation
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index c5b6c7b..8222155 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -16,6 +16,15 @@
package com.android.server.location;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -28,6 +37,7 @@ import android.hardware.location.GeofenceHardware;
import android.hardware.location.GeofenceHardwareImpl;
import android.location.Criteria;
import android.location.FusedBatchOptions;
+import android.location.GpsMeasurementsEvent;
import android.location.IGpsGeofenceHardware;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
@@ -46,7 +56,6 @@ import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -64,27 +73,17 @@ import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import android.util.NtpTrustedTime;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.location.GpsNetInitiatedHandler;
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
-import java.util.ArrayList;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.Date;
import java.util.Map.Entry;
import java.util.Properties;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
/**
* A GPS implementation of LocationProvider used by LocationManager.
@@ -314,7 +313,12 @@ public class GpsLocationProvider implements LocationProviderInterface {
private final ILocationManager mILocationManager;
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
private Bundle mLocationExtras = new Bundle();
- private ArrayList<Listener> mListeners = new ArrayList<Listener>();
+ private GpsStatusListenerHelper mListenerHelper = new GpsStatusListenerHelper() {
+ @Override
+ protected boolean isSupported() {
+ return native_is_measurement_supported();
+ }
+ };
// Handler for processing events
private Handler mHandler;
@@ -348,49 +352,29 @@ public class GpsLocationProvider implements LocationProviderInterface {
private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
@Override
public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
- if (listener == null) {
- throw new NullPointerException("listener is null in addGpsStatusListener");
- }
-
- synchronized (mListeners) {
- IBinder binder = listener.asBinder();
- int size = mListeners.size();
- for (int i = 0; i < size; i++) {
- Listener test = mListeners.get(i);
- if (binder.equals(test.mListener.asBinder())) {
- // listener already added
- return;
- }
- }
-
- Listener l = new Listener(listener);
- binder.linkToDeath(l, 0);
- mListeners.add(l);
- }
+ mListenerHelper.addListener(listener);
}
@Override
public void removeGpsStatusListener(IGpsStatusListener listener) {
- if (listener == null) {
- throw new NullPointerException("listener is null in addGpsStatusListener");
- }
+ mListenerHelper.removeListener(listener);
+ }
+ };
- synchronized (mListeners) {
- IBinder binder = listener.asBinder();
- Listener l = null;
- int size = mListeners.size();
- for (int i = 0; i < size && l == null; i++) {
- Listener test = mListeners.get(i);
- if (binder.equals(test.mListener.asBinder())) {
- l = test;
- }
- }
+ private final GpsMeasurementsProvider mGpsMeasurementsProvider = new GpsMeasurementsProvider() {
+ @Override
+ public boolean isSupported() {
+ return native_is_measurement_supported();
+ }
- if (l != null) {
- mListeners.remove(l);
- binder.unlinkToDeath(l, 0);
- }
- }
+ @Override
+ protected void onFirstListenerAdded() {
+ native_start_measurement_collection();
+ }
+
+ @Override
+ protected void onLastListenerRemoved() {
+ native_stop_measurement_collection();
}
};
@@ -402,6 +386,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
return mGpsGeofenceBinder;
}
+ public GpsMeasurementsProvider getGpsMeasurementsProvider() {
+ return mGpsMeasurementsProvider;
+ }
+
private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -892,26 +880,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
}
- private final class Listener implements IBinder.DeathRecipient {
- final IGpsStatusListener mListener;
-
- Listener(IGpsStatusListener listener) {
- mListener = listener;
- }
-
- @Override
- public void binderDied() {
- if (DEBUG) Log.d(TAG, "GPS status listener died");
-
- synchronized (mListeners) {
- mListeners.remove(this);
- }
- if (mListener != null) {
- mListener.asBinder().unlinkToDeath(this, 0);
- }
- }
- }
-
private void updateClientUids(WorkSource source) {
// Update work source.
WorkSource[] changes = mClientSource.setReturningDiffs(source);
@@ -1185,20 +1153,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
// notify status listeners
- synchronized (mListeners) {
- int size = mListeners.size();
- for (int i = 0; i < size; i++) {
- Listener listener = mListeners.get(i);
- try {
- listener.mListener.onFirstFix(mTimeToFirstFix);
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException in stopNavigating");
- mListeners.remove(listener);
- // adjust for size of list changing
- size--;
- }
- }
- }
+ mListenerHelper.onFirstFix(mTimeToFirstFix);
}
if (mSingleShot) {
@@ -1232,49 +1187,31 @@ public class GpsLocationProvider implements LocationProviderInterface {
private void reportStatus(int status) {
if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
- synchronized (mListeners) {
- boolean wasNavigating = mNavigating;
-
- switch (status) {
- case GPS_STATUS_SESSION_BEGIN:
- mNavigating = true;
- mEngineOn = true;
- break;
- case GPS_STATUS_SESSION_END:
- mNavigating = false;
- break;
- case GPS_STATUS_ENGINE_ON:
- mEngineOn = true;
- break;
- case GPS_STATUS_ENGINE_OFF:
- mEngineOn = false;
- mNavigating = false;
- break;
- }
+ boolean wasNavigating = mNavigating;
+ switch (status) {
+ case GPS_STATUS_SESSION_BEGIN:
+ mNavigating = true;
+ mEngineOn = true;
+ break;
+ case GPS_STATUS_SESSION_END:
+ mNavigating = false;
+ break;
+ case GPS_STATUS_ENGINE_ON:
+ mEngineOn = true;
+ break;
+ case GPS_STATUS_ENGINE_OFF:
+ mEngineOn = false;
+ mNavigating = false;
+ break;
+ }
- if (wasNavigating != mNavigating) {
- int size = mListeners.size();
- for (int i = 0; i < size; i++) {
- Listener listener = mListeners.get(i);
- try {
- if (mNavigating) {
- listener.mListener.onGpsStarted();
- } else {
- listener.mListener.onGpsStopped();
- }
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException in reportStatus");
- mListeners.remove(listener);
- // adjust for size of list changing
- size--;
- }
- }
+ if (wasNavigating != mNavigating) {
+ mListenerHelper.onStatusChanged(mNavigating);
- // send an intent to notify that the GPS has been enabled or disabled.
- Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
- intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
+ // send an intent to notify that the GPS has been enabled or disabled
+ Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
+ intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
@@ -1282,25 +1219,16 @@ public class GpsLocationProvider implements LocationProviderInterface {
* called from native code to update SV info
*/
private void reportSvStatus() {
-
int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
-
- synchronized (mListeners) {
- int size = mListeners.size();
- for (int i = 0; i < size; i++) {
- Listener listener = mListeners.get(i);
- try {
- listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
- mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
- mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException in reportSvInfo");
- mListeners.remove(listener);
- // adjust for size of list changing
- size--;
- }
- }
- }
+ mListenerHelper.onSvStatusChanged(
+ svCount,
+ mSvs,
+ mSnrs,
+ mSvElevations,
+ mSvAzimuths,
+ mSvMasks[EPHEMERIS_MASK],
+ mSvMasks[ALMANAC_MASK],
+ mSvMasks[USED_FOR_FIX_MASK]);
if (VERBOSE) {
Log.v(TAG, "SV count: " + svCount +
@@ -1398,26 +1326,16 @@ public class GpsLocationProvider implements LocationProviderInterface {
* called from native code to report NMEA data received
*/
private void reportNmea(long timestamp) {
- synchronized (mListeners) {
- int size = mListeners.size();
- if (size > 0) {
- // don't bother creating the String if we have no listeners
- int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
- String nmea = new String(mNmeaBuffer, 0, length);
-
- for (int i = 0; i < size; i++) {
- Listener listener = mListeners.get(i);
- try {
- listener.mListener.onNmeaReceived(timestamp, nmea);
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException in reportNmea");
- mListeners.remove(listener);
- // adjust for size of list changing
- size--;
- }
- }
- }
- }
+ int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
+ String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
+ mListenerHelper.onNmeaReceived(timestamp, nmea);
+ }
+
+ /**
+ * called from native code - Gps Data callback
+ */
+ private void reportMeasurementData(GpsMeasurementsEvent event) {
+ mGpsMeasurementsProvider.onMeasurementsAvailable(event);
}
/**
@@ -1845,7 +1763,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
Log.e(TAG, "No APN found to select.");
}
} catch (Exception e) {
- Log.e(TAG, "Error encountered on selectiong the APN.", e);
+ Log.e(TAG, "Error encountered on selecting the APN.", e);
} finally {
if (cursor != null) {
cursor.close();
@@ -2008,4 +1926,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
private static native boolean native_remove_geofence(int geofenceId);
private static native boolean native_resume_geofence(int geofenceId, int transitions);
private static native boolean native_pause_geofence(int geofenceId);
+
+ // Gps Hal measurements support.
+ private static native boolean native_is_measurement_supported();
+ private static native boolean native_start_measurement_collection();
+ private static native boolean native_stop_measurement_collection();
}
diff --git a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
new file mode 100644
index 0000000..001f638
--- /dev/null
+++ b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 com.android.server.location;
+
+import android.location.GpsMeasurementsEvent;
+import android.location.IGpsMeasurementsListener;
+import android.os.RemoteException;
+
+/**
+ * An base implementation for GPS measurements provider.
+ * It abstracts out the responsibility of handling listeners, while still allowing technology
+ * specific implementations to be built.
+ *
+ * @hide
+ */
+public abstract class GpsMeasurementsProvider
+ extends RemoteListenerHelper<IGpsMeasurementsListener> {
+
+ public void onMeasurementsAvailable(final GpsMeasurementsEvent event) {
+ ListenerOperation<IGpsMeasurementsListener> operation =
+ new ListenerOperation<IGpsMeasurementsListener>() {
+ @Override
+ public void execute(IGpsMeasurementsListener listener) throws RemoteException {
+ listener.onGpsMeasurementsReceived(event);
+ }
+ };
+
+ foreach(operation);
+ }
+}
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
new file mode 100644
index 0000000..b741e75
--- /dev/null
+++ b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 com.android.server.location;
+
+import android.location.IGpsStatusListener;
+import android.os.RemoteException;
+
+/**
+ * Implementation of a handler for {@link IGpsStatusListener}.
+ */
+abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
+ public void onFirstFix(final int timeToFirstFix) {
+ Operation operation = new Operation() {
+ @Override
+ public void execute(IGpsStatusListener listener) throws RemoteException {
+ listener.onFirstFix(timeToFirstFix);
+ }
+ };
+
+ foreach(operation);
+ }
+
+ public void onStatusChanged(final boolean isNavigating) {
+ Operation operation = new Operation() {
+ @Override
+ public void execute(IGpsStatusListener listener) throws RemoteException {
+ if (isNavigating) {
+ listener.onGpsStarted();
+ } else {
+ listener.onGpsStopped();
+ }
+ }
+ };
+
+ foreach(operation);
+ }
+
+ public void onSvStatusChanged(
+ final int svCount,
+ final int[] prns,
+ final float[] snrs,
+ final float[] elevations,
+ final float[] azimuths,
+ final int ephemerisMask,
+ final int almanacMask,
+ final int usedInFixMask) {
+ Operation operation = new Operation() {
+ @Override
+ public void execute(IGpsStatusListener listener) throws RemoteException {
+ listener.onSvStatusChanged(
+ svCount,
+ prns,
+ snrs,
+ elevations,
+ azimuths,
+ ephemerisMask,
+ almanacMask,
+ usedInFixMask);
+ }
+ };
+
+ foreach(operation);
+ }
+
+ public void onNmeaReceived(final long timestamp, final String nmea) {
+ Operation operation = new Operation() {
+ @Override
+ public void execute(IGpsStatusListener listener) throws RemoteException {
+ listener.onNmeaReceived(timestamp, nmea);
+ }
+ };
+
+ foreach(operation);
+ }
+
+ private abstract class Operation implements ListenerOperation<IGpsStatusListener> { }
+}
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
new file mode 100644
index 0000000..79335f7
--- /dev/null
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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 com.android.server.location;
+
+import com.android.internal.util.Preconditions;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+
+/**
+ * A helper class, that handles operations in remote listeners, and tracks for remote process death.
+ */
+abstract class RemoteListenerHelper<TListener extends IInterface> {
+ private static final String TAG = "RemoteListenerHelper";
+
+ private final HashMap<IBinder, LinkedListener> mListenerMap =
+ new HashMap<IBinder, LinkedListener>();
+
+ public boolean addListener(@NonNull TListener listener) {
+ Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
+
+ if (!isSupported()) {
+ Log.e(TAG, "Refused to add listener, the feature is not supported.");
+ return false;
+ }
+
+ IBinder binder = listener.asBinder();
+ LinkedListener deathListener = new LinkedListener(listener);
+ synchronized (mListenerMap) {
+ if (mListenerMap.containsKey(binder)) {
+ // listener already added
+ return true;
+ }
+
+ try {
+ binder.linkToDeath(deathListener, 0 /* flags */);
+ } catch (RemoteException e) {
+ // if the remote process registering the listener is already death, just swallow the
+ // exception and continue
+ Log.e(TAG, "Remote listener already died.", e);
+ return false;
+ }
+
+ mListenerMap.put(binder, deathListener);
+ if (mListenerMap.size() == 1) {
+ onFirstListenerAdded();
+ }
+ }
+
+ return true;
+ }
+
+ public boolean removeListener(@NonNull TListener listener) {
+ Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
+
+ if (!isSupported()) {
+ Log.e(TAG, "Refused to remove listener, the feature is not supported.");
+ return false;
+ }
+
+ IBinder binder = listener.asBinder();
+ LinkedListener linkedListener;
+ synchronized (mListenerMap) {
+ linkedListener = mListenerMap.remove(binder);
+ if (mListenerMap.isEmpty() && linkedListener != null) {
+ onLastListenerRemoved();
+ }
+ }
+
+ if (linkedListener != null) {
+ binder.unlinkToDeath(linkedListener, 0 /* flags */);
+ }
+
+ return true;
+ }
+
+ protected abstract boolean isSupported();
+
+ protected void onFirstListenerAdded() {
+ // event triggered when the first listener has been added
+ }
+
+ protected void onLastListenerRemoved() {
+ // event triggered when the last listener has bee removed
+ }
+
+ protected interface ListenerOperation<TListener extends IInterface> {
+ void execute(TListener listener) throws RemoteException;
+ }
+
+ protected void foreach(ListenerOperation operation) {
+ Collection<LinkedListener> linkedListeners;
+ synchronized (mListenerMap) {
+ Collection<LinkedListener> values = mListenerMap.values();
+ linkedListeners = new ArrayList<LinkedListener>(values);
+ }
+
+ for (LinkedListener linkedListener : linkedListeners) {
+ TListener listener = linkedListener.getUnderlyingListener();
+ try {
+ operation.execute(listener);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in monitored listener.", e);
+ removeListener(listener);
+ }
+ }
+ }
+
+ private class LinkedListener implements IBinder.DeathRecipient {
+ private final TListener mListener;
+
+ public LinkedListener(@NonNull TListener listener) {
+ mListener = listener;
+ }
+
+ @NonNull
+ public TListener getUnderlyingListener() {
+ return mListener;
+ }
+
+ @Override
+ public void binderDied() {
+ Log.d(TAG, "Remote Listener died: " + mListener);
+ removeListener(mListener);
+ }
+ }
+}
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 5bafb52..87626d0 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -52,6 +52,7 @@ static jmethodID method_reportGeofenceAddStatus;
static jmethodID method_reportGeofenceRemoveStatus;
static jmethodID method_reportGeofencePauseStatus;
static jmethodID method_reportGeofenceResumeStatus;
+static jmethodID method_reportMeasurementData;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
@@ -60,6 +61,7 @@ static const GpsNiInterface* sGpsNiInterface = NULL;
static const GpsDebugInterface* sGpsDebugInterface = NULL;
static const AGpsRilInterface* sAGpsRilInterface = NULL;
static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
+static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
// temporary storage for GPS callbacks
static GpsSvStatus sGpsSvStatus;
@@ -441,6 +443,10 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env,
"(II)V");
method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
"(II)V");
+ method_reportMeasurementData = env->GetMethodID(
+ clazz,
+ "reportMeasurementData",
+ "(Landroid/location/GpsMeasurementsEvent;)V");
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
@@ -464,6 +470,8 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env,
(const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
sGpsGeofencingInterface =
(const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
+ sGpsMeasurementInterface =
+ (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
}
}
@@ -851,42 +859,500 @@ static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* env
return JNI_FALSE;
}
+static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
+ const char* doubleSignature = "(D)V";
+
+ jclass gpsClockClass = env->FindClass("android/location/GpsClock");
+ jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
+
+ jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
+ GpsClockFlags flags = clock->flags;
+
+ if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
+ jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
+ env->CallObjectMethod(gpsClockObject, setterMethod, clock->leap_second);
+ }
+
+ jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", "(J)V");
+ env->CallObjectMethod(gpsClockObject, setterMethod, clock->time_ns);
+
+ if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsClockClass,
+ "setTimeUncertaintyInNs",
+ doubleSignature);
+ env->CallObjectMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
+ }
+
+ if (flags & GPS_CLOCK_HAS_BIAS) {
+ jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
+ env->CallObjectMethod(gpsClockObject, setterMethod, clock->bias_ns);
+ }
+
+ if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsClockClass,
+ "setBiasUncertaintyInNs",
+ doubleSignature);
+ env->CallObjectMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
+ }
+
+ if (flags & GPS_CLOCK_HAS_DRIFT) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsClockClass,
+ "setDriftInNsPerSec",
+ doubleSignature);
+ env->CallObjectMethod(gpsClockObject, setterMethod, clock->drift_nsps);
+ }
+
+ if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsClockClass,
+ "setDriftUncertaintyInNsPerSec",
+ doubleSignature);
+ env->CallObjectMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
+ }
+
+ return gpsClockObject;
+}
+
+static jobject translate_gps_measurement(
+ JNIEnv* env,
+ GpsMeasurement* measurement,
+ uint32_t time_ns) {
+ const char* shortSignature = "(S)V";
+ const char* longSignature = "(J)V";
+ const char* floatSignature = "(F)V";
+ const char* doubleSignature = "(D)V";
+
+ jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
+ jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
+
+ jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
+ GpsMeasurementFlags flags = measurement->flags;
+
+
+ jmethodID prnSetterMethod = env->GetMethodID(gpsMeasurementClass, "setPrn", "(B)V");
+ env->CallObjectMethod(gpsMeasurementObject, prnSetterMethod, measurement->prn);
+
+ jmethodID localTimeSetterMethod =
+ env->GetMethodID(gpsMeasurementClass, "setLocalTimeInNs", longSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ localTimeSetterMethod,
+ time_ns + measurement->time_offset_ns);
+
+ jmethodID receivedGpsTowSetterMethod =
+ env->GetMethodID(gpsMeasurementClass, "setReceivedGpsTowInNs", longSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ receivedGpsTowSetterMethod,
+ measurement->received_gps_tow_ns);
+
+ jmethodID cn0SetterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setCn0InDbHz",
+ doubleSignature);
+ env->CallObjectMethod(gpsMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
+
+ jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setPseudorangeRateInMetersPerSec",
+ doubleSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ pseudorangeRateSetterMethod,
+ measurement->pseudorange_rate_mpersec);
+
+ jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setPseudorangeRateUncertaintyInMetersPerSec",
+ doubleSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ pseudorangeRateUncertaintySetterMethod,
+ measurement->pseudorange_rate_uncertainty_mpersec);
+
+ jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setAccumulatedDeltaRangeInMeters",
+ doubleSignature);
+ env->CallVoidMethod(
+ gpsMeasurementObject,
+ accumulatedDeltaRangeSetterMethod,
+ measurement->accumulated_delta_range_m);
+
+ jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setAccumulatedDeltaRangeUncertaintyInMeters",
+ doubleSignature);
+ env->CallVoidMethod(
+ gpsMeasurementObject,
+ accumulatedDeltaRangeUncertaintySetterMethod,
+ measurement->accumulated_delta_range_uncertainty_m);
+
+
+ if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setPseudorangeInMeters",
+ doubleSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->pseudorange_m);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setPseudorangeUncertaintyInMeters",
+ doubleSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->pseudorange_uncertainty_m);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setCodePhaseInChips",
+ doubleSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->code_phase_chips);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setCodePhaseUncertaintyInChips",
+ doubleSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->code_phase_uncertainty_chips);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setCarrierFrequencyInHz",
+ floatSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->carrier_frequency_hz);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
+ jmethodID setterMethod =
+ env->GetMethodID(gpsMeasurementClass, "setCarrierCycles", longSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->carrier_cycles);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
+ jmethodID setterMethod =
+ env->GetMethodID(gpsMeasurementClass, "setCarrierPhase", doubleSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->carrier_phase);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setCarrierPhaseUncertainty",
+ doubleSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->carrier_phase_uncertainty);
+ }
+
+ jmethodID lossOfLockSetterMethod =
+ env->GetMethodID(gpsMeasurementClass, "setLossOfLock", shortSignature);
+ env->CallObjectMethod(gpsMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
+
+ if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setBitNumber",
+ shortSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->bit_number);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setTimeFromLastBitInNs",
+ longSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->time_from_last_bit_ns);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setDopplerShiftInHz",
+ doubleSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->doppler_shift_hz);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setDopplerShiftUncertaintyInHz",
+ doubleSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->doppler_shift_uncertainty_hz);
+ }
+
+ jmethodID multipathIndicatorSetterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setMultipathIndicator",
+ shortSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ multipathIndicatorSetterMethod,
+ measurement->multipath_indicator);
+
+ if (flags & GPS_MEASUREMENT_HAS_SNR) {
+ jmethodID setterMethod =
+ env->GetMethodID(gpsMeasurementClass, "setSnrInDb", doubleSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->snr_db);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setElevationInDeg",
+ doubleSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->elevation_deg);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setElevationUncertaintyInDeg",
+ doubleSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->elevation_uncertainty_deg);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
+ jmethodID setterMethod =
+ env->GetMethodID(gpsMeasurementClass, "setAzimuthInDeg", doubleSignature);
+ env->CallObjectMethod(gpsMeasurementObject, setterMethod, measurement->azimuth_deg);
+ }
+
+ if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
+ jmethodID setterMethod = env->GetMethodID(
+ gpsMeasurementClass,
+ "setAzimuthUncertaintyInDeg",
+ doubleSignature);
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ setterMethod,
+ measurement->azimuth_uncertainty_deg);
+ }
+
+ jmethodID usedInFixSetterMethod = env->GetMethodID(gpsMeasurementClass, "setUsedInFix", "(Z)V");
+ env->CallObjectMethod(
+ gpsMeasurementObject,
+ usedInFixSetterMethod,
+ (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+
+ return gpsMeasurementObject;
+}
+
+static jobjectArray translate_gps_measurements(JNIEnv* env, GpsData* data) {
+ size_t measurementCount = data->measurement_count;
+ if (measurementCount == 0) {
+ return NULL;
+ }
+
+ jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
+ jobjectArray gpsMeasurementArray = env->NewObjectArray(
+ measurementCount,
+ gpsMeasurementClass,
+ NULL /* initialElement */);
+
+ GpsMeasurement* gpsMeasurements = data->measurements;
+ for (uint16_t i = 0; i < measurementCount; ++i) {
+ jobject gpsMeasurement = translate_gps_measurement(
+ env,
+ &gpsMeasurements[i],
+ data->clock.time_ns);
+ env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
+ env->DeleteLocalRef(gpsMeasurement);
+ }
+
+ env->DeleteLocalRef(gpsMeasurementClass);
+ return gpsMeasurementArray;
+}
+
+static void measurement_callback(GpsData* data) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (data == NULL) {
+ ALOGE("Invalid data provided to gps_measurement_callback");
+ return;
+ }
+
+ if (data->size == sizeof(GpsData)) {
+ jobject gpsClock = translate_gps_clock(env, &data->clock);
+ jobjectArray measurementArray = translate_gps_measurements(env, data);
+
+ jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
+ jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
+ gpsMeasurementsEventClass,
+ "<init>",
+ "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
+
+ jobject gpsMeasurementsEvent = env->NewObject(
+ gpsMeasurementsEventClass,
+ gpsMeasurementsEventCtor,
+ gpsClock,
+ measurementArray);
+
+ env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ } else {
+ ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%d", data->size);
+ return;
+ }
+}
+
+GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
+ sizeof(GpsMeasurementCallbacks),
+ measurement_callback,
+};
+
+static jboolean android_location_GpsLocationProvider_is_measurement_supported(
+ JNIEnv* env,
+ jobject obj) {
+ if (sGpsMeasurementInterface != NULL) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_start_measurement_collection(
+ JNIEnv* env,
+ jobject obj) {
+ if (sGpsMeasurementInterface == NULL) {
+ ALOGE("Measurement interface is not available.");
+ return JNI_FALSE;
+ }
+
+ int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
+ if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
+ ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+static jboolean android_location_GpsLocationProvider_stop_measurement_collection(
+ JNIEnv* env,
+ jobject obj) {
+ if (sGpsMeasurementInterface == NULL) {
+ ALOGE("Measurement interface not available");
+ return JNI_FALSE;
+ }
+
+ sGpsMeasurementInterface->close();
+ return JNI_TRUE;
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
{"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
{"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
{"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
- {"native_set_position_mode", "(IIIII)Z", (void*)android_location_GpsLocationProvider_set_position_mode},
+ {"native_set_position_mode",
+ "(IIIII)Z",
+ (void*)android_location_GpsLocationProvider_set_position_mode},
{"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
{"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
- {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
- {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+ {"native_delete_aiding_data",
+ "(I)V",
+ (void*)android_location_GpsLocationProvider_delete_aiding_data},
+ {"native_read_sv_status",
+ "([I[F[F[F[I)I",
+ (void*)android_location_GpsLocationProvider_read_sv_status},
{"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
{"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
- {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
+ {"native_inject_location",
+ "(DDF)V",
+ (void*)android_location_GpsLocationProvider_inject_location},
{"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
- {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
- {"native_agps_data_conn_open", "(Ljava/lang/String;I)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
- {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
- {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
- {"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id},
- {"native_agps_set_ref_location_cellid","(IIIII)V",(void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
- {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
- {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
- {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
- {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
- {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
- {"native_is_geofence_supported", "()Z", (void*) android_location_GpsLocationProvider_is_geofence_supported},
- {"native_add_geofence", "(IDDDIIII)Z", (void *)android_location_GpsLocationProvider_add_geofence},
- {"native_remove_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_remove_geofence},
+ {"native_inject_xtra_data",
+ "([BI)V",
+ (void*)android_location_GpsLocationProvider_inject_xtra_data},
+ {"native_agps_data_conn_open",
+ "(Ljava/lang/String;I)V",
+ (void*)android_location_GpsLocationProvider_agps_data_conn_open},
+ {"native_agps_data_conn_closed",
+ "()V",
+ (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
+ {"native_agps_data_conn_failed",
+ "()V",
+ (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
+ {"native_agps_set_id",
+ "(ILjava/lang/String;)V",
+ (void*)android_location_GpsLocationProvider_agps_set_id},
+ {"native_agps_set_ref_location_cellid",
+ "(IIIII)V",
+ (void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
+ {"native_set_agps_server",
+ "(ILjava/lang/String;I)V",
+ (void*)android_location_GpsLocationProvider_set_agps_server},
+ {"native_send_ni_response",
+ "(II)V",
+ (void*)android_location_GpsLocationProvider_send_ni_response},
+ {"native_agps_ni_message",
+ "([BI)V",
+ (void *)android_location_GpsLocationProvider_agps_send_ni_message},
+ {"native_get_internal_state",
+ "()Ljava/lang/String;",
+ (void*)android_location_GpsLocationProvider_get_internal_state},
+ {"native_update_network_state",
+ "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
+ (void*)android_location_GpsLocationProvider_update_network_state },
+ {"native_is_geofence_supported",
+ "()Z",
+ (void*) android_location_GpsLocationProvider_is_geofence_supported},
+ {"native_add_geofence",
+ "(IDDDIIII)Z",
+ (void *)android_location_GpsLocationProvider_add_geofence},
+ {"native_remove_geofence",
+ "(I)Z",
+ (void *)android_location_GpsLocationProvider_remove_geofence},
{"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
- {"native_resume_geofence", "(II)Z", (void *)android_location_GpsLocationProvider_resume_geofence}
+ {"native_resume_geofence",
+ "(II)Z",
+ (void *)android_location_GpsLocationProvider_resume_geofence},
+ {"native_is_measurement_supported",
+ "()Z",
+ (void*) android_location_GpsLocationProvider_is_measurement_supported},
+ {"native_start_measurement_collection",
+ "()Z",
+ (void*) android_location_GpsLocationProvider_start_measurement_collection},
+ {"native_stop_measurement_collection",
+ "()Z",
+ (void*) android_location_GpsLocationProvider_stop_measurement_collection}
};
int register_android_server_location_GpsLocationProvider(JNIEnv* env)
{
- return jniRegisterNativeMethods(env, "com/android/server/location/GpsLocationProvider", sMethods, NELEM(sMethods));
+ return jniRegisterNativeMethods(
+ env,
+ "com/android/server/location/GpsLocationProvider",
+ sMethods,
+ NELEM(sMethods));
}
} /* namespace android */