summaryrefslogtreecommitdiffstats
path: root/location
diff options
context:
space:
mode:
Diffstat (limited to 'location')
-rw-r--r--location/java/android/location/FusedBatchOptions.java5
-rw-r--r--location/java/android/location/GpsClock.java512
-rw-r--r--location/java/android/location/GpsMeasurement.java1387
-rw-r--r--location/java/android/location/GpsMeasurementListenerTransport.java66
-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/GpsNavigationMessage.java276
-rw-r--r--location/java/android/location/GpsNavigationMessageEvent.aidl19
-rw-r--r--location/java/android/location/GpsNavigationMessageEvent.java92
-rw-r--r--location/java/android/location/GpsNavigationMessageListenerTransport.java69
-rw-r--r--location/java/android/location/IGpsMeasurementsListener.aidl26
-rw-r--r--location/java/android/location/IGpsNavigationMessageListener.aidl26
-rw-r--r--location/java/android/location/ILocationManager.aidl11
-rw-r--r--location/java/android/location/LocalListenerHelper.java109
-rw-r--r--location/java/android/location/Location.java9
-rw-r--r--location/java/android/location/LocationManager.java74
-rw-r--r--location/java/android/location/LocationRequest.java12
-rw-r--r--location/java/android/location/SettingInjectorService.java50
-rw-r--r--location/java/com/android/internal/location/GpsNetInitiatedHandler.java283
-rw-r--r--location/lib/java/com/android/location/provider/ActivityChangedEvent.java56
-rw-r--r--location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java70
-rw-r--r--location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java134
-rw-r--r--location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java86
-rw-r--r--location/lib/java/com/android/location/provider/GeofenceProvider.java3
-rw-r--r--location/lib/java/com/android/location/provider/LocationProviderBase.java1
25 files changed, 3418 insertions, 104 deletions
diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java
index 623d707..5600aeb 100644
--- a/location/java/android/location/FusedBatchOptions.java
+++ b/location/java/android/location/FusedBatchOptions.java
@@ -95,8 +95,9 @@ public class FusedBatchOptions implements Parcelable {
}
public static final class BatchFlags {
- public static int WAKEUP_ON_FIFO_FULL = 1<<0;
- public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+ // follow the definitions to the letter in fused_location.h
+ public static int WAKEUP_ON_FIFO_FULL = 0x0000001;
+ public static int CALLBACK_ON_LOCATION_FIX =0x0000002;
}
/*
diff --git a/location/java/android/location/GpsClock.java b/location/java/android/location/GpsClock.java
new file mode 100644
index 0000000..963b604
--- /dev/null
+++ b/location/java/android/location/GpsClock.java
@@ -0,0 +1,512 @@
+/*
+ * 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 containing a GPS clock timestamp.
+ * It represents a measurement of the GPS receiver's clock.
+ *
+ * @hide
+ */
+public class GpsClock implements Parcelable {
+ private static final String TAG = "GpsClock";
+
+ // The following enumerations must be in sync with the values declared in gps.h
+
+ /**
+ * The type of the time stored is not available or it is unknown.
+ */
+ public static final byte TYPE_UNKNOWN = 0;
+
+ /**
+ * The source of the time value reported by this class is the 'Local Hardware Clock'.
+ */
+ public static final byte TYPE_LOCAL_HW_TIME = 1;
+
+ /**
+ * The source of the time value reported by this class is the 'GPS time' derived from
+ * satellites (epoch = Jan 6, 1980).
+ */
+ public static final byte TYPE_GPS_TIME = 2;
+
+ private static final short HAS_NO_FLAGS = 0;
+ private static final short HAS_LEAP_SECOND = (1<<0);
+ private static final short HAS_TIME_UNCERTAINTY = (1<<1);
+ private static final short HAS_FULL_BIAS = (1<<2);
+ private static final short HAS_BIAS = (1<<3);
+ private static final short HAS_BIAS_UNCERTAINTY = (1<<4);
+ private static final short HAS_DRIFT = (1<<5);
+ private static final short HAS_DRIFT_UNCERTAINTY = (1<<6);
+
+ // End enumerations in sync with gps.h
+
+ private short mFlags;
+ private short mLeapSecond;
+ private byte mType;
+ private long mTimeInNs;
+ private double mTimeUncertaintyInNs;
+ private long mFullBiasInNs;
+ private double mBiasInNs;
+ private double mBiasUncertaintyInNs;
+ private double mDriftInNsPerSec;
+ private double mDriftUncertaintyInNsPerSec;
+
+ GpsClock() {
+ initialize();
+ }
+
+ /**
+ * Sets all contents to the values stored in the provided object.
+ */
+ public void set(GpsClock clock) {
+ mFlags = clock.mFlags;
+ mLeapSecond = clock.mLeapSecond;
+ mType = clock.mType;
+ mTimeInNs = clock.mTimeInNs;
+ mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
+ mFullBiasInNs = clock.mFullBiasInNs;
+ mBiasInNs = clock.mBiasInNs;
+ mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
+ mDriftInNsPerSec = clock.mDriftInNsPerSec;
+ mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
+ }
+
+ /**
+ * Resets all the contents to its original state.
+ */
+ public void reset() {
+ initialize();
+ }
+
+ /**
+ * Gets the type of time reported by {@link #getTimeInNs()}.
+ */
+ public byte getType() {
+ return mType;
+ }
+
+ /**
+ * Sets the type of time reported.
+ */
+ public void setType(byte value) {
+ switch (value) {
+ case TYPE_UNKNOWN:
+ case TYPE_GPS_TIME:
+ case TYPE_LOCAL_HW_TIME:
+ mType = value;
+ break;
+ default:
+ Log.d(TAG, "Sanitizing invalid 'type': " + value);
+ mType = TYPE_UNKNOWN;
+ break;
+ }
+ }
+
+ /**
+ * Gets a string representation of the 'type'.
+ * For internal and logging use only.
+ */
+ private String getTypeString() {
+ switch (mType) {
+ case TYPE_UNKNOWN:
+ return "Unknown";
+ case TYPE_GPS_TIME:
+ return "GpsTime";
+ case TYPE_LOCAL_HW_TIME:
+ return "LocalHwClock";
+ default:
+ return "<Invalid>";
+ }
+ }
+
+ /**
+ * Returns true if {@link #getLeapSecond()} is available, false otherwise.
+ */
+ public boolean hasLeapSecond() {
+ return isFlagSet(HAS_LEAP_SECOND);
+ }
+
+ /**
+ * Gets the leap second associated with the clock's time.
+ * The sign of the value is defined by the following equation:
+ * utc_time_ns = time_ns + (full_bias_ns + bias_ns) - leap_second * 1,000,000,000
+ *
+ * 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) {
+ setFlag(HAS_LEAP_SECOND);
+ mLeapSecond = leapSecond;
+ }
+
+ /**
+ * Resets the leap second associated with the clock's time.
+ */
+ public void resetLeapSecond() {
+ resetFlag(HAS_LEAP_SECOND);
+ mLeapSecond = Short.MIN_VALUE;
+ }
+
+ /**
+ * Gets the GPS receiver internal clock value in nanoseconds.
+ * This can be either the 'local hardware clock' value ({@link #TYPE_LOCAL_HW_TIME}), or the
+ * current GPS time derived inside GPS receiver ({@link #TYPE_GPS_TIME}).
+ * {@link #getType()} defines the time reported.
+ *
+ * For 'local hardware clock' this value is expected to be monotonically increasing during the
+ * reporting session. The real GPS time can be derived by compensating
+ * {@link #getFullBiasInNs()} (when it is available) from this value.
+ *
+ * For 'GPS time' this value is expected to be the best estimation of current GPS time that GPS
+ * receiver can achieve. {@link #getTimeUncertaintyInNs()} should be available when GPS time is
+ * specified.
+ *
+ * Sub-nanosecond accuracy can be provided by means of {@link #getBiasInNs()}.
+ * The reported time includes {@link #getTimeUncertaintyInNs()}.
+ */
+ public long getTimeInNs() {
+ return mTimeInNs;
+ }
+
+ /**
+ * Sets the GPS receiver internal clock in nanoseconds.
+ */
+ public void setTimeInNs(long timeInNs) {
+ mTimeInNs = timeInNs;
+ }
+
+ /**
+ * Returns true if {@link #getTimeUncertaintyInNs()} is available, false otherwise.
+ */
+ public boolean hasTimeUncertaintyInNs() {
+ return isFlagSet(HAS_TIME_UNCERTAINTY);
+ }
+
+ /**
+ * Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * 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) {
+ setFlag(HAS_TIME_UNCERTAINTY);
+ mTimeUncertaintyInNs = timeUncertaintyInNs;
+ }
+
+ /**
+ * Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
+ */
+ public void resetTimeUncertaintyInNs() {
+ resetFlag(HAS_TIME_UNCERTAINTY);
+ mTimeUncertaintyInNs = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link @getFullBiasInNs()} is available, false otherwise.
+ */
+ public boolean hasFullBiasInNs() {
+ return isFlagSet(HAS_FULL_BIAS);
+ }
+
+ /**
+ * Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
+ * the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
+ *
+ * This value is available if {@link #TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
+ * the clock for GPS time.
+ * {@link #getBiasUncertaintyInNs()} should be used for quality check.
+ *
+ * The sign of the value is defined by the following equation:
+ * true time (GPS time) = time_ns + (full_bias_ns + bias_ns)
+ *
+ * The reported full bias includes {@link #getBiasUncertaintyInNs()}.
+ * The value is onl available if {@link #hasFullBiasInNs()} is true.
+ */
+ public long getFullBiasInNs() {
+ return mFullBiasInNs;
+ }
+
+ /**
+ * Sets the full bias in nanoseconds.
+ */
+ public void setFullBiasInNs(long value) {
+ setFlag(HAS_FULL_BIAS);
+ mFullBiasInNs = value;
+ }
+
+ /**
+ * Resets the full bias in nanoseconds.
+ */
+ public void resetFullBiasInNs() {
+ resetFlag(HAS_FULL_BIAS);
+ mFullBiasInNs = Long.MIN_VALUE;
+ }
+
+ /**
+ * Returns true if {@link #getBiasInNs()} is available, false otherwise.
+ */
+ public boolean hasBiasInNs() {
+ return isFlagSet(HAS_BIAS);
+ }
+
+ /**
+ * Gets the clock's sub-nanosecond bias.
+ * The reported bias includes {@link #getBiasUncertaintyInNs()}.
+ *
+ * The value is only available if {@link #hasBiasInNs()} is true.
+ */
+ public double getBiasInNs() {
+ return mBiasInNs;
+ }
+
+ /**
+ * Sets the sub-nanosecond bias.
+ */
+ public void setBiasInNs(double biasInNs) {
+ setFlag(HAS_BIAS);
+ mBiasInNs = biasInNs;
+ }
+
+ /**
+ * Resets the clock's Bias in nanoseconds.
+ */
+ public void resetBiasInNs() {
+ resetFlag(HAS_BIAS);
+ mBiasInNs = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getBiasUncertaintyInNs()} is available, false otherwise.
+ */
+ public boolean hasBiasUncertaintyInNs() {
+ return isFlagSet(HAS_BIAS_UNCERTAINTY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_BIAS_UNCERTAINTY);
+ mBiasUncertaintyInNs = biasUncertaintyInNs;
+ }
+
+ /**
+ * Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
+ */
+ public void resetBiasUncertaintyInNs() {
+ resetFlag(HAS_BIAS_UNCERTAINTY);
+ mBiasUncertaintyInNs = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getDriftInNsPerSec()} is available, false otherwise.
+ */
+ public boolean hasDriftInNsPerSec() {
+ return isFlagSet(HAS_DRIFT);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_DRIFT);
+ mDriftInNsPerSec = driftInNsPerSec;
+ }
+
+ /**
+ * Resets the clock's Drift in nanoseconds per second.
+ */
+ public void resetDriftInNsPerSec() {
+ resetFlag(HAS_DRIFT);
+ mDriftInNsPerSec = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getDriftUncertaintyInNsPerSec()} is available, false otherwise.
+ */
+ public boolean hasDriftUncertaintyInNsPerSec() {
+ return isFlagSet(HAS_DRIFT_UNCERTAINTY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_DRIFT_UNCERTAINTY);
+ mDriftUncertaintyInNsPerSec = driftUncertaintyInNsPerSec;
+ }
+
+ /**
+ * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
+ */
+ public void resetDriftUncertaintyInNsPerSec() {
+ resetFlag(HAS_DRIFT_UNCERTAINTY);
+ mDriftUncertaintyInNsPerSec = Double.NaN;
+ }
+
+ public static final Creator<GpsClock> CREATOR = new Creator<GpsClock>() {
+ @Override
+ public GpsClock createFromParcel(Parcel parcel) {
+ GpsClock gpsClock = new GpsClock();
+
+ gpsClock.mFlags = (short) parcel.readInt();
+ gpsClock.mLeapSecond = (short) parcel.readInt();
+ gpsClock.mType = parcel.readByte();
+ gpsClock.mTimeInNs = parcel.readLong();
+ gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
+ gpsClock.mFullBiasInNs = parcel.readLong();
+ gpsClock.mBiasInNs = parcel.readDouble();
+ gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
+ gpsClock.mDriftInNsPerSec = parcel.readDouble();
+ gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
+
+ return gpsClock;
+ }
+
+ @Override
+ public GpsClock[] newArray(int size) {
+ return new GpsClock[size];
+ }
+ };
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mFlags);
+ parcel.writeInt(mLeapSecond);
+ parcel.writeByte(mType);
+ parcel.writeLong(mTimeInNs);
+ parcel.writeDouble(mTimeUncertaintyInNs);
+ parcel.writeLong(mFullBiasInNs);
+ parcel.writeDouble(mBiasInNs);
+ parcel.writeDouble(mBiasUncertaintyInNs);
+ parcel.writeDouble(mDriftInNsPerSec);
+ parcel.writeDouble(mDriftUncertaintyInNsPerSec);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ final String format = " %-15s = %s\n";
+ final String formatWithUncertainty = " %-15s = %-25s %-26s = %s\n";
+ StringBuilder builder = new StringBuilder("GpsClock:\n");
+
+ builder.append(String.format(format, "Type", getTypeString()));
+
+ builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "TimeInNs",
+ mTimeInNs,
+ "TimeUncertaintyInNs",
+ hasTimeUncertaintyInNs() ? mTimeUncertaintyInNs : null));
+
+ builder.append(String.format(
+ format,
+ "FullBiasInNs",
+ hasFullBiasInNs() ? mFullBiasInNs : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "BiasInNs",
+ hasBiasInNs() ? mBiasInNs : null,
+ "BiasUncertaintyInNs",
+ hasBiasUncertaintyInNs() ? mBiasUncertaintyInNs : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "DriftInNsPerSec",
+ hasDriftInNsPerSec() ? mDriftInNsPerSec : null,
+ "DriftUncertaintyInNsPerSec",
+ hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
+
+ return builder.toString();
+ }
+
+ private void initialize() {
+ mFlags = HAS_NO_FLAGS;
+ resetLeapSecond();
+ setType(TYPE_UNKNOWN);
+ setTimeInNs(Long.MIN_VALUE);
+ resetTimeUncertaintyInNs();
+ resetBiasInNs();
+ resetBiasUncertaintyInNs();
+ resetDriftInNsPerSec();
+ resetDriftUncertaintyInNsPerSec();
+ }
+
+ private void setFlag(short flag) {
+ mFlags |= flag;
+ }
+
+ private void resetFlag(short flag) {
+ mFlags &= ~flag;
+ }
+
+ private boolean isFlagSet(short flag) {
+ return (mFlags & flag) == flag;
+ }
+}
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
new file mode 100644
index 0000000..1550dc2
--- /dev/null
+++ b/location/java/android/location/GpsMeasurement.java
@@ -0,0 +1,1387 @@
+/*
+ * 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";
+
+ private int mFlags;
+ private byte mPrn;
+ private double mTimeOffsetInNs;
+ private short mState;
+ private long mReceivedGpsTowInNs;
+ private long mReceivedGpsTowUncertaintyInNs;
+ private double mCn0InDbHz;
+ private double mPseudorangeRateInMetersPerSec;
+ private double mPseudorangeRateUncertaintyInMetersPerSec;
+ private short mAccumulatedDeltaRangeState;
+ private double mAccumulatedDeltaRangeInMeters;
+ private double mAccumulatedDeltaRangeUncertaintyInMeters;
+ private double mPseudorangeInMeters;
+ private double mPseudorangeUncertaintyInMeters;
+ private double mCodePhaseInChips;
+ private double mCodePhaseUncertaintyInChips;
+ private float mCarrierFrequencyInHz;
+ private long mCarrierCycles;
+ private double mCarrierPhase;
+ private double mCarrierPhaseUncertainty;
+ private byte mLossOfLock;
+ private int mBitNumber;
+ private short mTimeFromLastBitInMs;
+ private double mDopplerShiftInHz;
+ private double mDopplerShiftUncertaintyInHz;
+ private byte mMultipathIndicator;
+ private double mSnrInDb;
+ private double mElevationInDeg;
+ private double mElevationUncertaintyInDeg;
+ private double mAzimuthInDeg;
+ private double mAzimuthUncertaintyInDeg;
+ private boolean mUsedInFix;
+
+ // The following enumerations must be in sync with the values declared in gps.h
+
+ private static final int HAS_NO_FLAGS = 0;
+ private static final int HAS_SNR = (1<<0);
+ private static final int HAS_ELEVATION = (1<<1);
+ private static final int HAS_ELEVATION_UNCERTAINTY = (1<<2);
+ private static final int HAS_AZIMUTH = (1<<3);
+ private static final int HAS_AZIMUTH_UNCERTAINTY = (1<<4);
+ private static final int HAS_PSEUDORANGE = (1<<5);
+ private static final int HAS_PSEUDORANGE_UNCERTAINTY = (1<<6);
+ private static final int HAS_CODE_PHASE = (1<<7);
+ private static final int HAS_CODE_PHASE_UNCERTAINTY = (1<<8);
+ private static final int HAS_CARRIER_FREQUENCY = (1<<9);
+ private static final int HAS_CARRIER_CYCLES = (1<<10);
+ private static final int HAS_CARRIER_PHASE = (1<<11);
+ private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
+ private static final int HAS_BIT_NUMBER = (1<<13);
+ private static final int HAS_TIME_FROM_LAST_BIT = (1<<14);
+ private static final int HAS_DOPPLER_SHIFT = (1<<15);
+ private static final int HAS_DOPPLER_SHIFT_UNCERTAINTY = (1<<16);
+
+ /**
+ * The indicator is not available or it is unknown.
+ */
+ public static final byte LOSS_OF_LOCK_UNKNOWN = 0;
+
+ /**
+ * The measurement does not present any indication of 'loss of lock'.
+ */
+ public static final byte LOSS_OF_LOCK_OK = 1;
+
+ /**
+ * 'Loss of lock' detected between the previous and current observation: cycle slip possible.
+ */
+ public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2;
+
+ /**
+ * The indicator is not available or it is unknown.
+ */
+ public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0;
+
+ /**
+ * The measurement has been indicated to use multi-path.
+ */
+ public static final byte MULTIPATH_INDICATOR_DETECTED = 1;
+
+ /**
+ * The measurement has been indicated not tu use multi-path.
+ */
+ public static final byte MULTIPATH_INDICATOR_NOT_USED = 2;
+
+ /**
+ * The state of GPS receiver the measurement is invalid or unknown.
+ */
+ public static final short STATE_UNKNOWN = 0;
+
+ /**
+ * The state of the GPS receiver is ranging code lock.
+ */
+ public static final short STATE_CODE_LOCK = (1<<0);
+
+ /**
+ * The state of the GPS receiver is in bit sync.
+ */
+ public static final short STATE_BIT_SYNC = (1<<1);
+
+ /**
+ *The state of the GPS receiver is in sub-frame sync.
+ */
+ public static final short STATE_SUBFRAME_SYNC = (1<<2);
+
+ /**
+ * The state of the GPS receiver has TOW decoded.
+ */
+ public static final short STATE_TOW_DECODED = (1<<3);
+
+ /**
+ * The state of the 'Accumulated Delta Range' is invalid or unknown.
+ */
+ public static final short ADR_STATE_UNKNOWN = 0;
+
+ /**
+ * The state of the 'Accumulated Delta Range' is valid.
+ */
+ public static final short ADR_STATE_VALID = (1<<0);
+
+ /**
+ * The state of the 'Accumulated Delta Range' has detected a reset.
+ */
+ public static final short ADR_STATE_RESET = (1<<1);
+
+ /**
+ * The state of the 'Accumulated Delta Range' has a cycle slip detected.
+ */
+ public static final short ADR_STATE_CYCLE_SLIP = (1<<2);
+
+ // End enumerations in sync with gps.h
+
+ GpsMeasurement() {
+ initialize();
+ }
+
+ /**
+ * Sets all contents to the values stored in the provided object.
+ */
+ public void set(GpsMeasurement measurement) {
+ mFlags = measurement.mFlags;
+ mPrn = measurement.mPrn;
+ mTimeOffsetInNs = measurement.mTimeOffsetInNs;
+ mState = measurement.mState;
+ mReceivedGpsTowInNs = measurement.mReceivedGpsTowInNs;
+ mReceivedGpsTowUncertaintyInNs = measurement.mReceivedGpsTowUncertaintyInNs;
+ mCn0InDbHz = measurement.mCn0InDbHz;
+ mPseudorangeRateInMetersPerSec = measurement.mPseudorangeRateInMetersPerSec;
+ mPseudorangeRateUncertaintyInMetersPerSec =
+ measurement.mPseudorangeRateUncertaintyInMetersPerSec;
+ mAccumulatedDeltaRangeState = measurement.mAccumulatedDeltaRangeState;
+ mAccumulatedDeltaRangeInMeters = measurement.mAccumulatedDeltaRangeInMeters;
+ mAccumulatedDeltaRangeUncertaintyInMeters =
+ measurement.mAccumulatedDeltaRangeUncertaintyInMeters;
+ mPseudorangeInMeters = measurement.mPseudorangeInMeters;
+ mPseudorangeUncertaintyInMeters = measurement.mPseudorangeUncertaintyInMeters;
+ mCodePhaseInChips = measurement.mCodePhaseInChips;
+ mCodePhaseUncertaintyInChips = measurement.mCodePhaseUncertaintyInChips;
+ mCarrierFrequencyInHz = measurement.mCarrierFrequencyInHz;
+ mCarrierCycles = measurement.mCarrierCycles;
+ mCarrierPhase = measurement.mCarrierPhase;
+ mCarrierPhaseUncertainty = measurement.mCarrierPhaseUncertainty;
+ mLossOfLock = measurement.mLossOfLock;
+ mBitNumber = measurement.mBitNumber;
+ mTimeFromLastBitInMs = measurement.mTimeFromLastBitInMs;
+ mDopplerShiftInHz = measurement.mDopplerShiftInHz;
+ mDopplerShiftUncertaintyInHz = measurement.mDopplerShiftUncertaintyInHz;
+ mMultipathIndicator = measurement.mMultipathIndicator;
+ mSnrInDb = measurement.mSnrInDb;
+ mElevationInDeg = measurement.mElevationInDeg;
+ mElevationUncertaintyInDeg = measurement.mElevationUncertaintyInDeg;
+ mAzimuthInDeg = measurement.mAzimuthInDeg;
+ mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
+ mUsedInFix = measurement.mUsedInFix;
+ }
+
+ /**
+ * Resets all the contents to its original state.
+ */
+ public void reset() {
+ initialize();
+ }
+
+ /**
+ * 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 time offset at which the measurement was taken in nanoseconds.
+ * The reference receiver's time is specified by {@link GpsClock#getTimeInNs()} and should be
+ * interpreted in the same way as indicated by {@link GpsClock#getType()}.
+ *
+ * The sign of this value is given by the following equation:
+ * measurement time = time_ns + time_offset_ns
+ *
+ * The value provides an individual time-stamp for the measurement, and allows sub-nanosecond
+ * accuracy.
+ */
+ public double getTimeOffsetInNs() {
+ return mTimeOffsetInNs;
+ }
+
+ /**
+ * Sets the time offset at which the measurement was taken in nanoseconds.
+ */
+ public void setTimeOffsetInNs(double value) {
+ mTimeOffsetInNs = value;
+ }
+
+ /**
+ * Gets per-satellite sync state.
+ * It represents the current sync state for the associated satellite.
+ *
+ * This value helps interpret {@link #getReceivedGpsTowInNs()}.
+ */
+ public short getState() {
+ return mState;
+ }
+
+ /**
+ * Sets the sync state.
+ */
+ public void setState(short value) {
+ switch (value) {
+ case STATE_UNKNOWN:
+ case STATE_BIT_SYNC:
+ case STATE_CODE_LOCK:
+ case STATE_SUBFRAME_SYNC:
+ case STATE_TOW_DECODED:
+ mState = value;
+ break;
+ default:
+ Log.d(TAG, "Sanitizing invalid 'sync state': " + value);
+ mState = STATE_UNKNOWN;
+ break;
+ }
+ }
+
+ /**
+ * Gets a string representation of the 'sync state'.
+ * For internal and logging use only.
+ */
+ private String getStateString() {
+ switch (mState) {
+ case STATE_UNKNOWN:
+ return "Unknown";
+ case STATE_BIT_SYNC:
+ return "BitSync";
+ case STATE_CODE_LOCK:
+ return "CodeLock";
+ case STATE_SUBFRAME_SYNC:
+ return "SubframeSync";
+ case STATE_TOW_DECODED:
+ return "TowDecoded";
+ default:
+ return "<Invalid>";
+ }
+ }
+
+ /**
+ * Gets the received GPS Time-of-Week at the measurement time, in nanoseconds.
+ * The value is relative to the beginning of the current GPS week.
+ *
+ * Given {@link #getState()} of the GPS receiver, the range of this field can be:
+ * Searching : [ 0 ] : {@link #STATE_UNKNOWN} is set
+ * Ranging code lock : [ 0 1 ms ] : {@link #STATE_CODE_LOCK} is set
+ * Bit sync : [ 0 20 ms ] : {@link #STATE_BIT_SYNC} is set
+ * Subframe sync : [ 0 6 ms ] : {@link #STATE_SUBFRAME_SYNC} is set
+ * TOW decoded : [ 0 1 week ] : {@link #STATE_TOW_DECODED} is set
+ */
+ public long getReceivedGpsTowInNs() {
+ return mReceivedGpsTowInNs;
+ }
+
+ /**
+ * Sets the received GPS time-of-week in nanoseconds.
+ */
+ public void setReceivedGpsTowInNs(long value) {
+ mReceivedGpsTowInNs = value;
+ }
+
+ /**
+ * Gets the received GPS time-of-week's uncertainty (1-Sigma) in nanoseconds.
+ */
+ public long getReceivedGpsTowUncertaintyInNs() {
+ return mReceivedGpsTowUncertaintyInNs;
+ }
+
+ /**
+ * Sets the received GPS time-of-week's uncertainty (1-Sigma) in nanoseconds.
+ */
+ public void setReceivedGpsTowUncertaintyInNs(long value) {
+ mReceivedGpsTowUncertaintyInNs = 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 'Accumulated Delta Range' state.
+ * It indicates whether {@link #getAccumulatedDeltaRangeInMeters()} is reset or there is a
+ * cycle slip (indicating 'loss of lock').
+ */
+ public short getAccumulatedDeltaRangeState() {
+ return mAccumulatedDeltaRangeState;
+ }
+
+ /**
+ * Sets the 'Accumulated Delta Range' state.
+ */
+ public void setAccumulatedDeltaRangeState(short value) {
+ switch (value) {
+ case ADR_STATE_UNKNOWN:
+ case ADR_STATE_VALID:
+ case ADR_STATE_RESET:
+ case ADR_STATE_CYCLE_SLIP:
+ mAccumulatedDeltaRangeState = value;
+ break;
+ default:
+ Log.d(TAG, "Sanitizing invalid 'Accumulated Delta Range state': " + value);
+ mAccumulatedDeltaRangeState = ADR_STATE_UNKNOWN;
+ break;
+ }
+ }
+
+ /**
+ * Gets a string representation of the 'Accumulated Delta Range state'.
+ * For internal and logging use only.
+ */
+ private String getAccumulatedDeltaRangeStateString() {
+ switch (mAccumulatedDeltaRangeState) {
+ case ADR_STATE_UNKNOWN:
+ return "Unknown";
+ case ADR_STATE_VALID:
+ return "Valid";
+ case ADR_STATE_RESET:
+ return "Reset";
+ case ADR_STATE_CYCLE_SLIP:
+ return "CycleSlip";
+ default:
+ return "<Invalid>";
+ }
+ }
+
+ /**
+ * Gets the accumulated delta range since the last channel reset, in meters.
+ * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyInMeters()}.
+ *
+ * The availability of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
+ */
+ 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.
+ *
+ * The availability of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
+ */
+ public void setAccumulatedDeltaRangeUncertaintyInMeters(double value) {
+ mAccumulatedDeltaRangeUncertaintyInMeters = value;
+ }
+
+ /**
+ * Returns true if {@link #getPseudorangeInMeters()} is available, false otherwise.
+ */
+ public boolean hasPseudorangeInMeters() {
+ return isFlagSet(HAS_PSEUDORANGE);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_PSEUDORANGE);
+ mPseudorangeInMeters = value;
+ }
+
+ /**
+ * Resets the Pseudo-range in meters.
+ */
+ public void resetPseudorangeInMeters() {
+ resetFlag(HAS_PSEUDORANGE);
+ mPseudorangeInMeters = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getPseudorangeUncertaintyInMeters()} is available, false otherwise.
+ */
+ public boolean hasPseudorangeUncertaintyInMeters() {
+ return isFlagSet(HAS_PSEUDORANGE_UNCERTAINTY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_PSEUDORANGE_UNCERTAINTY);
+ mPseudorangeUncertaintyInMeters = value;
+ }
+
+ /**
+ * Resets the pseudo-range's uncertainty (1-Sigma) in meters.
+ */
+ public void resetPseudorangeUncertaintyInMeters() {
+ resetFlag(HAS_PSEUDORANGE_UNCERTAINTY);
+ mPseudorangeUncertaintyInMeters = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCodePhaseInChips()} is available, false otherwise.
+ */
+ public boolean hasCodePhaseInChips() {
+ return isFlagSet(HAS_CODE_PHASE);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_CODE_PHASE);
+ mCodePhaseInChips = value;
+ }
+
+ /**
+ * Resets the Code-phase in chips.
+ */
+ public void resetCodePhaseInChips() {
+ resetFlag(HAS_CODE_PHASE);
+ mCodePhaseInChips = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCodePhaseUncertaintyInChips()} is available, false otherwise.
+ */
+ public boolean hasCodePhaseUncertaintyInChips() {
+ return isFlagSet(HAS_CODE_PHASE_UNCERTAINTY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_CODE_PHASE_UNCERTAINTY);
+ mCodePhaseUncertaintyInChips = value;
+ }
+
+ /**
+ * Resets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
+ */
+ public void resetCodePhaseUncertaintyInChips() {
+ resetFlag(HAS_CODE_PHASE_UNCERTAINTY);
+ mCodePhaseUncertaintyInChips = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCarrierFrequencyInHz()} is available, false otherwise.
+ */
+ public boolean hasCarrierFrequencyInHz() {
+ return isFlagSet(HAS_CARRIER_FREQUENCY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_CARRIER_FREQUENCY);
+ mCarrierFrequencyInHz = carrierFrequencyInHz;
+ }
+
+ /**
+ * Resets the Carrier frequency (L1 or L2) in Hz.
+ */
+ public void resetCarrierFrequencyInHz() {
+ resetFlag(HAS_CARRIER_FREQUENCY);
+ mCarrierFrequencyInHz = Float.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCarrierCycles()} is available, false otherwise.
+ */
+ public boolean hasCarrierCycles() {
+ return isFlagSet(HAS_CARRIER_CYCLES);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_CARRIER_CYCLES);
+ mCarrierCycles = value;
+ }
+
+ /**
+ * Resets the number of full carrier cycles between the satellite and the receiver.
+ */
+ public void resetCarrierCycles() {
+ resetFlag(HAS_CARRIER_CYCLES);
+ mCarrierCycles = Long.MIN_VALUE;
+ }
+
+ /**
+ * Returns true if {@link #getCarrierPhase()} is available, false otherwise.
+ */
+ public boolean hasCarrierPhase() {
+ return isFlagSet(HAS_CARRIER_PHASE);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_CARRIER_PHASE);
+ mCarrierPhase = value;
+ }
+
+ /**
+ * Resets the RF phase detected by the receiver.
+ */
+ public void resetCarrierPhase() {
+ resetFlag(HAS_CARRIER_PHASE);
+ mCarrierPhase = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getCarrierPhaseUncertainty()} is available, false otherwise.
+ */
+ public boolean hasCarrierPhaseUncertainty() {
+ return isFlagSet(HAS_CARRIER_PHASE_UNCERTAINTY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
+ mCarrierPhaseUncertainty = value;
+ }
+
+ /**
+ * Resets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+ */
+ public void resetCarrierPhaseUncertainty() {
+ resetFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
+ mCarrierPhaseUncertainty = Double.NaN;
+ }
+
+ /**
+ * Gets a value indicating the 'loss of lock' state of the event.
+ */
+ public byte getLossOfLock() {
+ return mLossOfLock;
+ }
+
+ /**
+ * Sets the 'loss of lock' status.
+ */
+ public void setLossOfLock(byte 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 isFlagSet(HAS_BIT_NUMBER);
+ }
+
+ /**
+ * Gets the number of GPS bits transmitted since Sat-Sun midnight (GPS week).
+ *
+ * The value is only available if {@link #hasBitNumber()} is true.
+ */
+ public int getBitNumber() {
+ return mBitNumber;
+ }
+
+ /**
+ * Sets the bit number within the broadcast frame.
+ */
+ public void setBitNumber(int bitNumber) {
+ setFlag(HAS_BIT_NUMBER);
+ mBitNumber = bitNumber;
+ }
+
+ /**
+ * Resets the bit number within the broadcast frame.
+ */
+ public void resetBitNumber() {
+ resetFlag(HAS_BIT_NUMBER);
+ mBitNumber = Integer.MIN_VALUE;
+ }
+
+ /**
+ * Returns true if {@link #getTimeFromLastBitInMs()} is available, false otherwise.
+ */
+ public boolean hasTimeFromLastBitInMs() {
+ return isFlagSet(HAS_TIME_FROM_LAST_BIT);
+ }
+
+ /**
+ * Gets the elapsed time since the last received bit in milliseconds.
+ * Range: [0, 20].
+ *
+ * The value is only available if {@link #hasTimeFromLastBitInMs()} is true.
+ */
+ public short getTimeFromLastBitInMs() {
+ return mTimeFromLastBitInMs;
+ }
+
+ /**
+ * Sets the elapsed time since the last received bit in milliseconds.
+ */
+ public void setTimeFromLastBitInMs(short value) {
+ setFlag(HAS_TIME_FROM_LAST_BIT);
+ mTimeFromLastBitInMs = value;
+ }
+
+ /**
+ * Resets the elapsed time since the last received bit in milliseconds.
+ */
+ public void resetTimeFromLastBitInMs() {
+ resetFlag(HAS_TIME_FROM_LAST_BIT);
+ mTimeFromLastBitInMs = Short.MIN_VALUE;
+ }
+
+ /**
+ * Returns true if {@link #getDopplerShiftInHz()} is available, false otherwise.
+ */
+ public boolean hasDopplerShiftInHz() {
+ return isFlagSet(HAS_DOPPLER_SHIFT);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_DOPPLER_SHIFT);
+ mDopplerShiftInHz = value;
+ }
+
+ /**
+ * Resets the Doppler shift in Hz.
+ */
+ public void resetDopplerShiftInHz() {
+ resetFlag(HAS_DOPPLER_SHIFT);
+ mDopplerShiftInHz = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getDopplerShiftUncertaintyInHz()} is available, false otherwise.
+ */
+ public boolean hasDopplerShiftUncertaintyInHz() {
+ return isFlagSet(HAS_DOPPLER_SHIFT_UNCERTAINTY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY);
+ mDopplerShiftUncertaintyInHz = value;
+ }
+
+ /**
+ * Resets the Doppler's shift uncertainty (1-Sigma) in Hz.
+ */
+ public void resetDopplerShiftUncertaintyInHz() {
+ resetFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY);
+ mDopplerShiftUncertaintyInHz = Double.NaN;
+ }
+
+ /**
+ * Gets a value indicating the 'multipath' state of the event.
+ */
+ public byte getMultipathIndicator() {
+ return mMultipathIndicator;
+ }
+
+ /**
+ * Sets the 'multi-path' indicator.
+ */
+ public void setMultipathIndicator(byte 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 "NotUsed";
+ default:
+ return "<Invalid>";
+ }
+ }
+
+ /**
+ * Returns true if {@link #getSnrInDb()} is available, false otherwise.
+ */
+ public boolean hasSnrInDb() {
+ return isFlagSet(HAS_SNR);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_SNR);
+ mSnrInDb = snrInDb;
+ }
+
+ /**
+ * Resets the Signal-to-noise ratio (SNR) in dB.
+ */
+ public void resetSnrInDb() {
+ resetFlag(HAS_SNR);
+ mSnrInDb = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getElevationInDeg()} is available, false otherwise.
+ */
+ public boolean hasElevationInDeg() {
+ return isFlagSet(HAS_ELEVATION);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_ELEVATION);
+ mElevationInDeg = elevationInDeg;
+ }
+
+ /**
+ * Resets the Elevation in degrees.
+ */
+ public void resetElevationInDeg() {
+ resetFlag(HAS_ELEVATION);
+ mElevationInDeg = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getElevationUncertaintyInDeg()} is available, false otherwise.
+ */
+ public boolean hasElevationUncertaintyInDeg() {
+ return isFlagSet(HAS_ELEVATION_UNCERTAINTY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_ELEVATION_UNCERTAINTY);
+ mElevationUncertaintyInDeg = value;
+ }
+
+ /**
+ * Resets the elevation's uncertainty (1-Sigma) in degrees.
+ */
+ public void resetElevationUncertaintyInDeg() {
+ resetFlag(HAS_ELEVATION_UNCERTAINTY);
+ mElevationUncertaintyInDeg = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getAzimuthInDeg()} is available, false otherwise.
+ */
+ public boolean hasAzimuthInDeg() {
+ return isFlagSet(HAS_AZIMUTH);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_AZIMUTH);
+ mAzimuthInDeg = value;
+ }
+
+ /**
+ * Resets the Azimuth in degrees.
+ */
+ public void resetAzimuthInDeg() {
+ resetFlag(HAS_AZIMUTH);
+ mAzimuthInDeg = Double.NaN;
+ }
+
+ /**
+ * Returns true if {@link #getAzimuthUncertaintyInDeg()} is available, false otherwise.
+ */
+ public boolean hasAzimuthUncertaintyInDeg() {
+ return isFlagSet(HAS_AZIMUTH_UNCERTAINTY);
+ }
+
+ /**
+ * 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) {
+ setFlag(HAS_AZIMUTH_UNCERTAINTY);
+ mAzimuthUncertaintyInDeg = value;
+ }
+
+ /**
+ * Resets the Azimuth's uncertainty (1-Sigma) in degrees.
+ */
+ public void resetAzimuthUncertaintyInDeg() {
+ resetFlag(HAS_AZIMUTH_UNCERTAINTY);
+ 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.mFlags = parcel.readInt();
+ gpsMeasurement.mPrn = parcel.readByte();
+ gpsMeasurement.mTimeOffsetInNs = parcel.readDouble();
+ gpsMeasurement.mState = (short) parcel.readInt();
+ gpsMeasurement.mReceivedGpsTowInNs = parcel.readLong();
+ gpsMeasurement.mReceivedGpsTowUncertaintyInNs = parcel.readLong();
+ gpsMeasurement.mCn0InDbHz = parcel.readDouble();
+ gpsMeasurement.mPseudorangeRateInMetersPerSec = parcel.readDouble();
+ gpsMeasurement.mPseudorangeRateUncertaintyInMetersPerSec = parcel.readDouble();
+ gpsMeasurement.mAccumulatedDeltaRangeState = (short) parcel.readInt();
+ gpsMeasurement.mAccumulatedDeltaRangeInMeters = parcel.readDouble();
+ gpsMeasurement.mAccumulatedDeltaRangeUncertaintyInMeters = parcel.readDouble();
+ gpsMeasurement.mPseudorangeInMeters = parcel.readDouble();
+ gpsMeasurement.mPseudorangeUncertaintyInMeters = parcel.readDouble();
+ gpsMeasurement.mCodePhaseInChips = parcel.readDouble();
+ gpsMeasurement.mCodePhaseUncertaintyInChips = parcel.readDouble();
+ gpsMeasurement.mCarrierFrequencyInHz = parcel.readFloat();
+ gpsMeasurement.mCarrierCycles = parcel.readLong();
+ gpsMeasurement.mCarrierPhase = parcel.readDouble();
+ gpsMeasurement.mCarrierPhaseUncertainty = parcel.readDouble();
+ gpsMeasurement.mLossOfLock = parcel.readByte();
+ gpsMeasurement.mBitNumber = parcel.readInt();
+ gpsMeasurement.mTimeFromLastBitInMs = (short) parcel.readInt();
+ gpsMeasurement.mDopplerShiftInHz = parcel.readDouble();
+ gpsMeasurement.mDopplerShiftUncertaintyInHz = parcel.readDouble();
+ gpsMeasurement.mMultipathIndicator = parcel.readByte();
+ gpsMeasurement.mSnrInDb = parcel.readDouble();
+ gpsMeasurement.mElevationInDeg = parcel.readDouble();
+ gpsMeasurement.mElevationUncertaintyInDeg = parcel.readDouble();
+ gpsMeasurement.mAzimuthInDeg = parcel.readDouble();
+ 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.writeInt(mFlags);
+ parcel.writeByte(mPrn);
+ parcel.writeDouble(mTimeOffsetInNs);
+ parcel.writeInt(mState);
+ parcel.writeLong(mReceivedGpsTowInNs);
+ parcel.writeLong(mReceivedGpsTowUncertaintyInNs);
+ parcel.writeDouble(mCn0InDbHz);
+ parcel.writeDouble(mPseudorangeRateInMetersPerSec);
+ parcel.writeDouble(mPseudorangeRateUncertaintyInMetersPerSec);
+ parcel.writeInt(mAccumulatedDeltaRangeState);
+ parcel.writeDouble(mAccumulatedDeltaRangeInMeters);
+ parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyInMeters);
+ parcel.writeDouble(mPseudorangeInMeters);
+ parcel.writeDouble(mPseudorangeUncertaintyInMeters);
+ parcel.writeDouble(mCodePhaseInChips);
+ parcel.writeDouble(mCodePhaseUncertaintyInChips);
+ parcel.writeFloat(mCarrierFrequencyInHz);
+ parcel.writeLong(mCarrierCycles);
+ parcel.writeDouble(mCarrierPhase);
+ parcel.writeDouble(mCarrierPhaseUncertainty);
+ parcel.writeByte(mLossOfLock);
+ parcel.writeInt(mBitNumber);
+ parcel.writeInt(mTimeFromLastBitInMs);
+ parcel.writeDouble(mDopplerShiftInHz);
+ parcel.writeDouble(mDopplerShiftUncertaintyInHz);
+ parcel.writeByte(mMultipathIndicator);
+ parcel.writeDouble(mSnrInDb);
+ parcel.writeDouble(mElevationInDeg);
+ parcel.writeDouble(mElevationUncertaintyInDeg);
+ parcel.writeDouble(mAzimuthInDeg);
+ 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, "TimeOffsetInNs", mTimeOffsetInNs));
+
+ builder.append(String.format(format, "State", getStateString()));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "ReceivedGpsTowInNs",
+ mReceivedGpsTowInNs,
+ "ReceivedGpsTowUncertaintyInNs",
+ mReceivedGpsTowUncertaintyInNs));
+
+ builder.append(String.format(format, "Cn0InDbHz", mCn0InDbHz));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "PseudorangeRateInMetersPerSec",
+ mPseudorangeRateInMetersPerSec,
+ "PseudorangeRateUncertaintyInMetersPerSec",
+ mPseudorangeRateUncertaintyInMetersPerSec));
+
+ builder.append(String.format(
+ format,
+ "AccumulatedDeltaRangeState",
+ getAccumulatedDeltaRangeStateString()));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "AccumulatedDeltaRangeInMeters",
+ mAccumulatedDeltaRangeInMeters,
+ "AccumulatedDeltaRangeUncertaintyInMeters",
+ mAccumulatedDeltaRangeUncertaintyInMeters));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "PseudorangeInMeters",
+ hasPseudorangeInMeters() ? mPseudorangeInMeters : null,
+ "PseudorangeUncertaintyInMeters",
+ hasPseudorangeUncertaintyInMeters() ? mPseudorangeUncertaintyInMeters : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "CodePhaseInChips",
+ hasCodePhaseInChips() ? mCodePhaseInChips : null,
+ "CodePhaseUncertaintyInChips",
+ hasCodePhaseUncertaintyInChips() ? mCodePhaseUncertaintyInChips : null));
+
+ builder.append(String.format(
+ format,
+ "CarrierFrequencyInHz",
+ hasCarrierFrequencyInHz() ? mCarrierFrequencyInHz : null));
+
+ builder.append(String.format(
+ format,
+ "CarrierCycles",
+ hasCarrierCycles() ? mCarrierCycles : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "CarrierPhase",
+ hasCarrierPhase() ? mCarrierPhase : null,
+ "CarrierPhaseUncertainty",
+ hasCarrierPhaseUncertainty() ? mCarrierPhaseUncertainty : null));
+
+ builder.append(String.format(format, "LossOfLock", getLossOfLockString()));
+
+ builder.append(String.format(
+ format,
+ "BitNumber",
+ hasBitNumber() ? mBitNumber : null));
+
+ builder.append(String.format(
+ format,
+ "TimeFromLastBitInMs",
+ hasTimeFromLastBitInMs() ? mTimeFromLastBitInMs : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "DopplerShiftInHz",
+ hasDopplerShiftInHz() ? mDopplerShiftInHz : null,
+ "DopplerShiftUncertaintyInHz",
+ hasDopplerShiftUncertaintyInHz() ? mDopplerShiftUncertaintyInHz : null));
+
+ builder.append(String.format(format, "MultipathIndicator", getMultipathIndicatorString()));
+
+ builder.append(String.format(
+ format,
+ "SnrInDb",
+ hasSnrInDb() ? mSnrInDb : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "ElevationInDeg",
+ hasElevationInDeg() ? mElevationInDeg : null,
+ "ElevationUncertaintyInDeg",
+ hasElevationUncertaintyInDeg() ? mElevationUncertaintyInDeg : null));
+
+ builder.append(String.format(
+ formatWithUncertainty,
+ "AzimuthInDeg",
+ hasAzimuthInDeg() ? mAzimuthInDeg : null,
+ "AzimuthUncertaintyInDeg",
+ hasAzimuthUncertaintyInDeg() ? mAzimuthUncertaintyInDeg : null));
+
+ builder.append(String.format(format, "UsedInFix", mUsedInFix));
+
+ return builder.toString();
+ }
+
+ private void initialize() {
+ mFlags = HAS_NO_FLAGS;
+ setPrn(Byte.MIN_VALUE);
+ setTimeOffsetInNs(Long.MIN_VALUE);
+ setState(STATE_UNKNOWN);
+ setReceivedGpsTowInNs(Long.MIN_VALUE);
+ setReceivedGpsTowUncertaintyInNs(Long.MAX_VALUE);
+ setCn0InDbHz(Double.MIN_VALUE);
+ setPseudorangeRateInMetersPerSec(Double.MIN_VALUE);
+ setPseudorangeRateUncertaintyInMetersPerSec(Double.MIN_VALUE);
+ setAccumulatedDeltaRangeState(ADR_STATE_UNKNOWN);
+ setAccumulatedDeltaRangeInMeters(Double.MIN_VALUE);
+ setAccumulatedDeltaRangeUncertaintyInMeters(Double.MIN_VALUE);
+ resetPseudorangeInMeters();
+ resetPseudorangeUncertaintyInMeters();
+ resetCodePhaseInChips();
+ resetCodePhaseUncertaintyInChips();
+ resetCarrierFrequencyInHz();
+ resetCarrierCycles();
+ resetCarrierPhase();
+ resetCarrierPhaseUncertainty();
+ setLossOfLock(LOSS_OF_LOCK_UNKNOWN);
+ resetBitNumber();
+ resetTimeFromLastBitInMs();
+ resetDopplerShiftInHz();
+ resetDopplerShiftUncertaintyInHz();
+ setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
+ resetSnrInDb();
+ resetElevationInDeg();
+ resetElevationUncertaintyInDeg();
+ resetAzimuthInDeg();
+ resetAzimuthUncertaintyInDeg();
+ setUsedInFix(false);
+ }
+
+ private void setFlag(int flag) {
+ mFlags |= flag;
+ }
+
+ private void resetFlag(int flag) {
+ mFlags &= ~flag;
+ }
+
+ private boolean isFlagSet(int flag) {
+ return (mFlags & flag) == flag;
+ }
+}
diff --git a/location/java/android/location/GpsMeasurementListenerTransport.java b/location/java/android/location/GpsMeasurementListenerTransport.java
new file mode 100644
index 0000000..2d9a372
--- /dev/null
+++ b/location/java/android/location/GpsMeasurementListenerTransport.java
@@ -0,0 +1,66 @@
+/*
+ * 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.content.Context;
+import android.os.RemoteException;
+
+/**
+ * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener}.
+ *
+ * @hide
+ */
+class GpsMeasurementListenerTransport
+ extends LocalListenerHelper<GpsMeasurementsEvent.Listener> {
+ private final Context mContext;
+ private final ILocationManager mLocationManager;
+
+ private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
+
+ public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) {
+ super("GpsMeasurementListenerTransport");
+ mContext = context;
+ mLocationManager = locationManager;
+ }
+
+ @Override
+ protected boolean registerWithServer() throws RemoteException {
+ return mLocationManager.addGpsMeasurementsListener(
+ mListenerTransport,
+ mContext.getPackageName());
+ }
+
+ @Override
+ protected void unregisterFromServer() throws RemoteException {
+ mLocationManager.removeGpsMeasurementsListener(mListenerTransport);
+ }
+
+ private class ListenerTransport extends IGpsMeasurementsListener.Stub {
+ @Override
+ public void onGpsMeasurementsReceived(final GpsMeasurementsEvent event) {
+ ListenerOperation<GpsMeasurementsEvent.Listener> operation =
+ new ListenerOperation<GpsMeasurementsEvent.Listener>() {
+ @Override
+ public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
+ listener.onGpsMeasurementsReceived(event);
+ }
+ };
+
+ foreach(operation);
+ }
+ }
+}
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/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
new file mode 100644
index 0000000..2eb4708
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -0,0 +1,276 @@
+/*
+ * 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 android.util.Log;
+
+import java.security.InvalidParameterException;
+
+/**
+ * A class containing a GPS satellite Navigation Message.
+ *
+ * @hide
+ */
+public class GpsNavigationMessage implements Parcelable {
+ private static final String TAG = "GpsNavigationMessage";
+ private static final byte[] EMPTY_ARRAY = new byte[0];
+
+ // The following enumerations must be in sync with the values declared in gps.h
+
+ /**
+ * The type of the navigation message is not available or unknown.
+ */
+ public static final byte TYPE_UNKNOWN = 0;
+
+ /**
+ * The Navigation Message is of type L1 C/A.
+ */
+ public static final byte TYPE_L1CA = 1;
+
+ /**
+ * The Navigation Message is of type L1-CNAV.
+ */
+ public static final byte TYPE_L2CNAV = 2;
+
+ /**
+ * The Navigation Message is of type L5-CNAV.
+ */
+ public static final byte TYPE_L5CNAV = 3;
+
+ /**
+ * The Navigation Message is of type CNAV-2.
+ */
+ public static final byte TYPE_CNAV2 = 4;
+
+ // End enumerations in sync with gps.h
+
+ private byte mType;
+ private byte mPrn;
+ private short mMessageId;
+ private short mSubmessageId;
+ private byte[] mData;
+
+ GpsNavigationMessage() {
+ initialize();
+ }
+
+ /**
+ * Sets all contents to the values stored in the provided object.
+ */
+ public void set(GpsNavigationMessage navigationMessage) {
+ mType = navigationMessage.mType;
+ mPrn = navigationMessage.mPrn;
+ mMessageId = navigationMessage.mMessageId;
+ mSubmessageId = navigationMessage.mSubmessageId;
+ mData = navigationMessage.mData;
+ }
+
+ /**
+ * Resets all the contents to its original state.
+ */
+ public void reset() {
+ initialize();
+ }
+
+ /**
+ * Gets the type of the navigation message contained in the object.
+ */
+ public byte getType() {
+ return mType;
+ }
+
+ /**
+ * Sets the type of the navigation message.
+ */
+ public void setType(byte value) {
+ switch (value) {
+ case TYPE_UNKNOWN:
+ case TYPE_L1CA:
+ case TYPE_L2CNAV:
+ case TYPE_L5CNAV:
+ case TYPE_CNAV2:
+ mType = value;
+ break;
+ default:
+ Log.d(TAG, "Sanitizing invalid 'type': " + value);
+ mType = TYPE_UNKNOWN;
+ break;
+ }
+ }
+
+ /**
+ * Gets a string representation of the 'type'.
+ * For internal and logging use only.
+ */
+ private String getTypeString() {
+ switch (mType) {
+ case TYPE_UNKNOWN:
+ return "Unknown";
+ case TYPE_L1CA:
+ return "L1 C/A";
+ case TYPE_L2CNAV:
+ return "L2-CNAV";
+ case TYPE_L5CNAV:
+ return "L5-CNAV";
+ case TYPE_CNAV2:
+ return "CNAV-2";
+ default:
+ return "<Invalid>";
+ }
+ }
+
+ /**
+ * Gets the Pseudo-random number.
+ * Range: [1, 32].
+ */
+ public byte getPrn() {
+ return mPrn;
+ }
+
+ /**
+ * Sets the Pseud-random number.
+ */
+ public void setPrn(byte value) {
+ mPrn = value;
+ }
+
+ /**
+ * Gets the Message Identifier.
+ * It provides an index so the complete Navigation Message can be assembled. i.e. for L1 C/A
+ * subframe 4 and 5, this value corresponds to the 'frame id' of the navigation message.
+ * Subframe 1, 2, 3 does not contain a 'frame id' and this might be reported as -1.
+ */
+ public short getMessageId() {
+ return mMessageId;
+ }
+
+ /**
+ * Sets the Message Identifier.
+ */
+ public void setMessageId(short value) {
+ mMessageId = value;
+ }
+
+ /**
+ * Gets the Sub-message Identifier.
+ * If required by {@link #getType()}, this value contains a sub-index within the current message
+ * (or frame) that is being transmitted. i.e. for L1 C/A the sub-message identifier corresponds
+ * to the sub-frame Id of the navigation message.
+ */
+ public short getSubmessageId() {
+ return mSubmessageId;
+ }
+
+ /**
+ * Sets the Sub-message identifier.
+ */
+ public void setSubmessageId(short value) {
+ mSubmessageId = value;
+ }
+
+ /**
+ * Gets the data associated with the Navigation Message.
+ * The bytes (or words) specified using big endian format (MSB first).
+ */
+ @NonNull
+ public byte[] getData() {
+ return mData;
+ }
+
+ /**
+ * Sets the data associated with the Navigation Message.
+ */
+ public void setData(byte[] value) {
+ if (value == null) {
+ throw new InvalidParameterException("Data must be a non-null array");
+ }
+
+ mData = value;
+ }
+
+ public static final Creator<GpsNavigationMessage> CREATOR =
+ new Creator<GpsNavigationMessage>() {
+ @Override
+ public GpsNavigationMessage createFromParcel(Parcel parcel) {
+ GpsNavigationMessage navigationMessage = new GpsNavigationMessage();
+
+ navigationMessage.setType(parcel.readByte());
+ navigationMessage.setPrn(parcel.readByte());
+ navigationMessage.setMessageId((short) parcel.readInt());
+ navigationMessage.setSubmessageId((short) parcel.readInt());
+
+ int dataLength = parcel.readInt();
+ byte[] data = new byte[dataLength];
+ parcel.readByteArray(data);
+ navigationMessage.setData(data);
+
+ return navigationMessage;
+ }
+
+ @Override
+ public GpsNavigationMessage[] newArray(int size) {
+ return new GpsNavigationMessage[size];
+ }
+ };
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeByte(mType);
+ parcel.writeByte(mPrn);
+ parcel.writeInt(mMessageId);
+ parcel.writeInt(mSubmessageId);
+ parcel.writeInt(mData.length);
+ parcel.writeByteArray(mData);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ final String format = " %-15s = %s\n";
+ StringBuilder builder = new StringBuilder("GpsNavigationMessage:\n");
+
+ builder.append(String.format(format, "Type", getTypeString()));
+ builder.append(String.format(format, "Prn", mPrn));
+ builder.append(String.format(format, "MessageId", mMessageId));
+ builder.append(String.format(format, "SubmessageId", mSubmessageId));
+
+ builder.append(String.format(format, "Data", "{"));
+ String prefix = " ";
+ for(byte value : mData) {
+ builder.append(prefix);
+ builder.append(value);
+ prefix = ", ";
+ }
+ builder.append(" }");
+
+ return builder.toString();
+ }
+
+ private void initialize() {
+ mType = TYPE_UNKNOWN;
+ mPrn = 0;
+ mMessageId = -1;
+ mSubmessageId = -1;
+ mData = EMPTY_ARRAY;
+ }
+}
diff --git a/location/java/android/location/GpsNavigationMessageEvent.aidl b/location/java/android/location/GpsNavigationMessageEvent.aidl
new file mode 100644
index 0000000..f84c2f7
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageEvent.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 GpsNavigationMessageEvent;
diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java
new file mode 100644
index 0000000..50ffa75
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageEvent.java
@@ -0,0 +1,92 @@
+/*
+ * 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 navigation message event.
+ * Events are delivered to registered instances of {@link Listener}.
+ *
+ * @hide
+ */
+public class GpsNavigationMessageEvent implements Parcelable {
+ private final GpsNavigationMessage mNavigationMessage;
+
+ /**
+ * Used for receiving GPS satellite Navigation Messages from the GPS engine.
+ * You can implement this interface and call
+ * {@link LocationManager#addGpsNavigationMessageListener}.
+ *
+ * @hide
+ */
+ public interface Listener {
+ void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event);
+ }
+
+ public GpsNavigationMessageEvent(GpsNavigationMessage message) {
+ if (message == null) {
+ throw new InvalidParameterException("Parameter 'message' must not be null.");
+ }
+ mNavigationMessage = message;
+ }
+
+ @NonNull
+ public GpsNavigationMessage getNavigationMessage() {
+ return mNavigationMessage;
+ }
+
+ public static final Creator<GpsNavigationMessageEvent> CREATOR =
+ new Creator<GpsNavigationMessageEvent>() {
+ @Override
+ public GpsNavigationMessageEvent createFromParcel(Parcel in) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ GpsNavigationMessage navigationMessage = in.readParcelable(classLoader);
+ return new GpsNavigationMessageEvent(navigationMessage);
+ }
+
+ @Override
+ public GpsNavigationMessageEvent[] newArray(int size) {
+ return new GpsNavigationMessageEvent[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mNavigationMessage, flags);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("[ GpsNavigationMessageEvent:\n\n");
+ builder.append(mNavigationMessage.toString());
+ builder.append("\n]");
+ return builder.toString();
+ }
+}
diff --git a/location/java/android/location/GpsNavigationMessageListenerTransport.java b/location/java/android/location/GpsNavigationMessageListenerTransport.java
new file mode 100644
index 0000000..ec4812b
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageListenerTransport.java
@@ -0,0 +1,69 @@
+/*
+ * 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.content.Context;
+import android.os.RemoteException;
+
+/**
+ * A handler class to manage transport listeners for {@link GpsNavigationMessageEvent.Listener}.
+ *
+ * @hide
+ */
+class GpsNavigationMessageListenerTransport
+ extends LocalListenerHelper<GpsNavigationMessageEvent.Listener> {
+ private final Context mContext;
+ private final ILocationManager mLocationManager;
+
+ private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport();
+
+ public GpsNavigationMessageListenerTransport(
+ Context context,
+ ILocationManager locationManager) {
+ super("GpsNavigationMessageListenerTransport");
+ mContext = context;
+ mLocationManager = locationManager;
+ }
+
+ @Override
+ protected boolean registerWithServer() throws RemoteException {
+ return mLocationManager.addGpsNavigationMessageListener(
+ mListenerTransport,
+ mContext.getPackageName());
+ }
+
+ @Override
+ protected void unregisterFromServer() throws RemoteException {
+ mLocationManager.removeGpsNavigationMessageListener(mListenerTransport);
+ }
+
+ private class ListenerTransport extends IGpsNavigationMessageListener.Stub {
+ @Override
+ public void onGpsNavigationMessageReceived(final GpsNavigationMessageEvent event) {
+ ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
+ new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
+ @Override
+ public void execute(GpsNavigationMessageEvent.Listener listener)
+ throws RemoteException {
+ listener.onGpsNavigationMessageReceived(event);
+ }
+ };
+
+ foreach(operation);
+ }
+ }
+}
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/IGpsNavigationMessageListener.aidl b/location/java/android/location/IGpsNavigationMessageListener.aidl
new file mode 100644
index 0000000..18603fe
--- /dev/null
+++ b/location/java/android/location/IGpsNavigationMessageListener.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.GpsNavigationMessageEvent;
+
+/**
+ * {@hide}
+ */
+oneway interface IGpsNavigationMessageListener {
+ void onGpsNavigationMessageReceived(in GpsNavigationMessageEvent event);
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index c353ec6..1501710 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -21,7 +21,8 @@ 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.IGpsNavigationMessageListener;
import android.location.IGpsStatusListener;
import android.location.ILocationListener;
import android.location.Location;
@@ -60,6 +61,14 @@ interface ILocationManager
boolean sendNiResponse(int notifId, int userResponse);
+ boolean addGpsMeasurementsListener(in IGpsMeasurementsListener listener, in String packageName);
+ boolean removeGpsMeasurementsListener(in IGpsMeasurementsListener listener);
+
+ boolean addGpsNavigationMessageListener(
+ in IGpsNavigationMessageListener listener,
+ in String packageName);
+ boolean removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener);
+
// --- deprecated ---
List<String> getAllProviders();
List<String> getProviders(in Criteria criteria, boolean enabledOnly);
diff --git a/location/java/android/location/LocalListenerHelper.java b/location/java/android/location/LocalListenerHelper.java
new file mode 100644
index 0000000..1f3bf67
--- /dev/null
+++ b/location/java/android/location/LocalListenerHelper.java
@@ -0,0 +1,109 @@
+/*
+ * 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.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * A base handler class to manage transport and local listeners.
+ *
+ * @hide
+ */
+abstract class LocalListenerHelper<TListener> {
+ private final HashSet<TListener> mListeners = new HashSet<TListener>();
+ private final String mTag;
+
+ protected LocalListenerHelper(String name) {
+ Preconditions.checkNotNull(name);
+ mTag = name;
+ }
+
+ public boolean add(@NonNull TListener 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 registeredWithService;
+ try {
+ registeredWithService = registerWithServer();
+ } catch (RemoteException e) {
+ Log.e(mTag, "Error handling first listener.", e);
+ return false;
+ }
+ if (!registeredWithService) {
+ Log.e(mTag, "Unable to register listener transport.");
+ return false;
+ }
+ }
+
+ if (mListeners.contains(listener)) {
+ return true;
+ }
+ mListeners.add(listener);
+ }
+ return true;
+ }
+
+ public void remove(@NonNull TListener listener) {
+ Preconditions.checkNotNull(listener);
+
+ synchronized (mListeners) {
+ boolean removed = mListeners.remove(listener);
+ boolean isLastRemoved = removed && mListeners.isEmpty();
+ if (isLastRemoved) {
+ try {
+ unregisterFromServer();
+ } catch (RemoteException e) {
+
+ }
+ }
+ }
+ }
+
+ protected abstract boolean registerWithServer() throws RemoteException;
+ protected abstract void unregisterFromServer() throws RemoteException;
+
+ protected interface ListenerOperation<TListener> {
+ void execute(TListener listener) throws RemoteException;
+ }
+
+ protected void foreach(ListenerOperation operation) {
+ Collection<TListener> listeners;
+ synchronized (mListeners) {
+ listeners = new ArrayList<TListener>(mListeners);
+ }
+
+ for (TListener listener : listeners) {
+ try {
+ operation.execute(listener);
+ } catch (RemoteException e) {
+ Log.e(mTag, "Error in monitored listener.", e);
+ // don't return, give a fair chance to all listeners to receive the event
+ }
+ }
+ }
+}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index f70110c..fcf222b 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -16,6 +16,7 @@
package android.location;
+import android.annotation.SystemApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -583,7 +584,8 @@ public class Location implements Parcelable {
}
/**
- * Get the altitude if available, in meters above sea level.
+ * Get the altitude if available, in meters above the WGS 84 reference
+ * ellipsoid.
*
* <p>If this location does not have an altitude then 0.0 is returned.
*/
@@ -592,7 +594,7 @@ public class Location implements Parcelable {
}
/**
- * Set the altitude, in meters above sea level.
+ * Set the altitude, in meters above the WGS 84 reference ellipsoid.
*
* <p>Following this call {@link #hasAltitude} will return true.
*/
@@ -770,6 +772,7 @@ public class Location implements Parcelable {
* @see #makeComplete
* @hide
*/
+ @SystemApi
public boolean isComplete() {
if (mProvider == null) return false;
if (!mHasAccuracy) return false;
@@ -787,6 +790,7 @@ public class Location implements Parcelable {
* @see #isComplete
* @hide
*/
+ @SystemApi
public void makeComplete() {
if (mProvider == null) mProvider = "?";
if (!mHasAccuracy) {
@@ -956,6 +960,7 @@ public class Location implements Parcelable {
* @param isFromMockProvider true if this Location came from a mock provider, false otherwise
* @hide
*/
+ @SystemApi
public void setIsFromMockProvider(boolean isFromMockProvider) {
mIsFromMockProvider = isFromMockProvider;
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index ccb4304..0445869 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -16,24 +16,24 @@
package android.location;
+import com.android.internal.location.ProviderProperties;
+
+import android.annotation.SystemApi;
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.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
@@ -59,6 +59,8 @@ public class LocationManager {
private final Context mContext;
private final ILocationManager mService;
+ private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport;
+ private final GpsNavigationMessageListenerTransport mGpsNavigationMessageListenerTransport;
private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
@@ -309,6 +311,9 @@ public class LocationManager {
public LocationManager(Context context, ILocationManager service) {
mService = service;
mContext = context;
+ mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService);
+ mGpsNavigationMessageListenerTransport =
+ new GpsNavigationMessageListenerTransport(mContext, mService);
}
private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -804,6 +809,7 @@ public class LocationManager {
*
* @hide
*/
+ @SystemApi
public void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper) {
checkListener(listener);
@@ -831,6 +837,7 @@ public class LocationManager {
*
* @hide
*/
+ @SystemApi
public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
checkPendingIntent(intent);
requestLocationUpdates(request, null, null, intent);
@@ -1104,11 +1111,15 @@ public class LocationManager {
* unless they depend on provider-specific APIs such as
* {@link #requestLocationUpdates(String, long, float, LocationListener)}.
*
+ * <p>
+ * Before API version {@link android.os.Build.VERSION_CODES#L}, this
+ * method would throw {@link SecurityException} if the location permissions
+ * were not sufficient to use the specified provider.
+ *
* @param provider the name of the provider
* @return true if the provider exists and is enabled
*
* @throws IllegalArgumentException if provider is null
- * @throws SecurityException if no suitable permission is present
*/
public boolean isProviderEnabled(String provider) {
checkProvider(provider);
@@ -1564,6 +1575,53 @@ public class LocationManager {
}
}
+ /**
+ * Adds a GPS Measurement listener.
+ *
+ * @param listener a {@link 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);
+ }
+
+ /**
+ * Adds a GPS Navigation Message listener.
+ *
+ * @param listener a {@link GpsNavigationMessageEvent.Listener} object to register.
+ * @return {@code true} if the listener was successfully registered, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
+ return mGpsNavigationMessageListenerTransport.add(listener);
+ }
+
+ /**
+ * Removes a GPS Navigation Message listener.
+ *
+ * @param listener a {@link GpsNavigationMessageEvent.Listener} object to remove.
+ *
+ * @hide
+ */
+ public void removeGpsNavigationMessageListener(
+ GpsNavigationMessageEvent.Listener listener) {
+ mGpsNavigationMessageListenerTransport.remove(listener);
+ }
+
/**
* Retrieves information about the current status of the GPS engine.
* This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
@@ -1610,7 +1668,7 @@ public class LocationManager {
* @hide
*/
public boolean sendNiResponse(int notifId, int userResponse) {
- try {
+ try {
return mService.sendNiResponse(notifId, userResponse);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in sendNiResponse: ", e);
@@ -1642,7 +1700,7 @@ public class LocationManager {
}
if (!intent.isTargetedToPackage()) {
IllegalArgumentException e = new IllegalArgumentException(
- "pending intent msut be targeted to package");
+ "pending intent must be targeted to package");
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
throw e;
} else {
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index c9162fe..271f2bb 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -16,6 +16,7 @@
package android.location;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -84,6 +85,7 @@ import android.util.TimeUtils;
*
* @hide
*/
+@SystemApi
public final class LocationRequest implements Parcelable {
/**
* Used with {@link #setQuality} to request the most accurate locations available.
@@ -166,6 +168,7 @@ public final class LocationRequest implements Parcelable {
}
/** @hide */
+ @SystemApi
public static LocationRequest createFromDeprecatedProvider(String provider, long minTime,
float minDistance, boolean singleShot) {
if (minTime < 0) minTime = 0;
@@ -191,6 +194,7 @@ public final class LocationRequest implements Parcelable {
}
/** @hide */
+ @SystemApi
public static LocationRequest createFromDeprecatedCriteria(Criteria criteria, long minTime,
float minDistance, boolean singleShot) {
if (minTime < 0) minTime = 0;
@@ -475,6 +479,7 @@ public final class LocationRequest implements Parcelable {
/** @hide */
+ @SystemApi
public LocationRequest setProvider(String provider) {
checkProvider(provider);
mProvider = provider;
@@ -482,11 +487,13 @@ public final class LocationRequest implements Parcelable {
}
/** @hide */
+ @SystemApi
public String getProvider() {
return mProvider;
}
/** @hide */
+ @SystemApi
public LocationRequest setSmallestDisplacement(float meters) {
checkDisplacement(meters);
mSmallestDisplacement = meters;
@@ -494,6 +501,7 @@ public final class LocationRequest implements Parcelable {
}
/** @hide */
+ @SystemApi
public float getSmallestDisplacement() {
return mSmallestDisplacement;
}
@@ -508,11 +516,13 @@ public final class LocationRequest implements Parcelable {
* @param workSource WorkSource defining power blame for this location request.
* @hide
*/
+ @SystemApi
public void setWorkSource(WorkSource workSource) {
mWorkSource = workSource;
}
/** @hide */
+ @SystemApi
public WorkSource getWorkSource() {
return mWorkSource;
}
@@ -531,11 +541,13 @@ public final class LocationRequest implements Parcelable {
* @see android.app.AppOpsManager
* @hide
*/
+ @SystemApi
public void setHideFromAppOps(boolean hideFromAppOps) {
mHideFromAppOps = hideFromAppOps;
}
/** @hide */
+ @SystemApi
public boolean getHideFromAppOps() {
return mHideFromAppOps;
}
diff --git a/location/java/android/location/SettingInjectorService.java b/location/java/android/location/SettingInjectorService.java
index 9f321f3..fcd2cde 100644
--- a/location/java/android/location/SettingInjectorService.java
+++ b/location/java/android/location/SettingInjectorService.java
@@ -26,7 +26,7 @@ import android.os.RemoteException;
import android.util.Log;
/**
- * Dynamically specifies the summary (subtitle) and enabled status of a preference injected into
+ * Dynamically specifies the enabled status of a preference injected into
* the list of app settings displayed by the system settings app
* <p/>
* For use only by apps that are included in the system image, for preferences that affect multiple
@@ -71,13 +71,12 @@ import android.util.Log;
* </ul>
*
* To ensure a good user experience, your {@link android.app.Application#onCreate()},
- * {@link #onGetSummary()}, and {@link #onGetEnabled()} methods must all be fast. If any are slow,
- * it can delay the display of settings values for other apps as well. Note further that all are
- * called on your app's UI thread.
+ * and {@link #onGetEnabled()} methods must all be fast. If either is slow,
+ * it can delay the display of settings values for other apps as well. Note further that these
+ * methods are called on your app's UI thread.
* <p/>
* For compactness, only one copy of a given setting should be injected. If each account has a
- * distinct value for the setting, then the {@link #onGetSummary()} value should represent a summary
- * of the state across all of the accounts and {@code settingsActivity} should display the value for
+ * distinct value for the setting, then only {@code settingsActivity} should display the value for
* each account.
*/
public abstract class SettingInjectorService extends Service {
@@ -109,14 +108,6 @@ public abstract class SettingInjectorService extends Service {
"android.location.InjectedSettingChanged";
/**
- * Name of the bundle key for the string specifying the summary for the setting (e.g., "ON" or
- * "OFF").
- *
- * @hide
- */
- public static final String SUMMARY_KEY = "summary";
-
- /**
* Name of the bundle key for the string specifying whether the setting is currently enabled.
*
* @hide
@@ -160,42 +151,31 @@ public abstract class SettingInjectorService extends Service {
private void onHandleIntent(Intent intent) {
- String summary;
- try {
- summary = onGetSummary();
- } catch (RuntimeException e) {
- // Exception. Send status anyway, so that settings injector can immediately start
- // loading the status of the next setting.
- sendStatus(intent, null, true);
- throw e;
- }
-
boolean enabled;
try {
enabled = onGetEnabled();
} catch (RuntimeException e) {
// Exception. Send status anyway, so that settings injector can immediately start
// loading the status of the next setting.
- sendStatus(intent, summary, true);
+ sendStatus(intent, true);
throw e;
}
- sendStatus(intent, summary, enabled);
+ sendStatus(intent, enabled);
}
/**
- * Send the summary and enabled values back to the caller via the messenger encoded in the
+ * Send the enabled values back to the caller via the messenger encoded in the
* intent.
*/
- private void sendStatus(Intent intent, String summary, boolean enabled) {
+ private void sendStatus(Intent intent, boolean enabled) {
Message message = Message.obtain();
Bundle bundle = new Bundle();
- bundle.putString(SUMMARY_KEY, summary);
bundle.putBoolean(ENABLED_KEY, enabled);
message.setData(bundle);
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, mName + ": received " + intent + ", summary=" + summary
+ Log.d(TAG, mName + ": received " + intent
+ ", enabled=" + enabled + ", sending message: " + message);
}
@@ -208,12 +188,14 @@ public abstract class SettingInjectorService extends Service {
}
/**
- * Returns the {@link android.preference.Preference#getSummary()} value (allowed to be null or
- * empty). Should not perform unpredictably-long operations such as network access--see the
- * running-time comments in the class-level javadoc.
+ * This method is no longer called, because status values are no longer shown for any injected
+ * setting.
+ *
+ * @return ignored
*
- * @return the {@link android.preference.Preference#getSummary()} value
+ * @deprecated not called any more
*/
+ @Deprecated
protected abstract String onGetSummary();
/**
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 57e2786..e9e475c 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -21,16 +21,25 @@ import java.io.UnsupportedEncodingException;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.location.LocationManager;
+import android.location.INetInitiatedListener;
+import android.telephony.TelephonyManager;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.PhoneStateListener;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.SystemProperties;
+import android.provider.Settings;
import android.util.Log;
import com.android.internal.R;
import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.TelephonyProperties;
/**
* A GPS Network-initiated Handler class used by LocationManager.
@@ -46,55 +55,70 @@ public class GpsNetInitiatedHandler {
// NI verify activity for bringing up UI (not used yet)
public static final String ACTION_NI_VERIFY = "android.intent.action.NETWORK_INITIATED_VERIFY";
-
+
// string constants for defining data fields in NI Intent
public static final String NI_INTENT_KEY_NOTIF_ID = "notif_id";
public static final String NI_INTENT_KEY_TITLE = "title";
public static final String NI_INTENT_KEY_MESSAGE = "message";
public static final String NI_INTENT_KEY_TIMEOUT = "timeout";
public static final String NI_INTENT_KEY_DEFAULT_RESPONSE = "default_resp";
-
+
// the extra command to send NI response to GpsLocationProvider
public static final String NI_RESPONSE_EXTRA_CMD = "send_ni_response";
-
+
// the extra command parameter names in the Bundle
public static final String NI_EXTRA_CMD_NOTIF_ID = "notif_id";
public static final String NI_EXTRA_CMD_RESPONSE = "response";
-
+
// these need to match GpsNiType constants in gps_ni.h
public static final int GPS_NI_TYPE_VOICE = 1;
public static final int GPS_NI_TYPE_UMTS_SUPL = 2;
public static final int GPS_NI_TYPE_UMTS_CTRL_PLANE = 3;
-
- // these need to match GpsUserResponseType constants in gps_ni.h
+ public static final int GPS_NI_TYPE_EMERGENCY_SUPL = 4;
+
+ // these need to match GpsUserResponseType constants in gps_ni.h
public static final int GPS_NI_RESPONSE_ACCEPT = 1;
public static final int GPS_NI_RESPONSE_DENY = 2;
- public static final int GPS_NI_RESPONSE_NORESP = 3;
-
+ public static final int GPS_NI_RESPONSE_NORESP = 3;
+ public static final int GPS_NI_RESPONSE_IGNORE = 4;
+
// these need to match GpsNiNotifyFlags constants in gps_ni.h
public static final int GPS_NI_NEED_NOTIFY = 0x0001;
public static final int GPS_NI_NEED_VERIFY = 0x0002;
public static final int GPS_NI_PRIVACY_OVERRIDE = 0x0004;
-
+
// these need to match GpsNiEncodingType in gps_ni.h
public static final int GPS_ENC_NONE = 0;
public static final int GPS_ENC_SUPL_GSM_DEFAULT = 1;
public static final int GPS_ENC_SUPL_UTF8 = 2;
public static final int GPS_ENC_SUPL_UCS2 = 3;
public static final int GPS_ENC_UNKNOWN = -1;
-
+
private final Context mContext;
-
+ private final TelephonyManager mTelephonyManager;
+ private final PhoneStateListener mPhoneStateListener;
+
// parent gps location provider
private final LocationManager mLocationManager;
-
+
// configuration of notificaiton behavior
private boolean mPlaySounds = false;
private boolean mPopupImmediately = true;
-
- // Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
+
+ // read the SUPL_ES form gps.conf
+ private volatile boolean mIsSuplEsEnabled;
+
+ // Set to true if the phone is having emergency call.
+ private volatile boolean mIsInEmergency;
+
+ // If Location function is enabled.
+ private volatile boolean mIsLocationEnabled = false;
+
+ private final INetInitiatedListener mNetInitiatedListener;
+
+ // Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
static private boolean mIsHexInput = true;
-
+
public static class GpsNiNotification
{
public int notificationId;
@@ -110,58 +134,137 @@ public class GpsNetInitiatedHandler {
public int textEncoding;
public Bundle extras;
};
-
+
public static class GpsNiResponse {
- /* User reponse, one of the values in GpsUserResponseType */
+ /* User response, one of the values in GpsUserResponseType */
int userResponse;
/* Optional extra data to pass with the user response */
Bundle extras;
};
-
+
+ private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
+
+ @Override public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
+ String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
+ /*
+ Emergency Mode is when during emergency call or in emergency call back mode.
+ For checking if it is during emergency call:
+ mIsInEmergency records if the phone is in emergency call or not. It will
+ be set to true when the phone is having emergency call, and then will
+ be set to false by mPhoneStateListener when the emergency call ends.
+ For checking if it is in emergency call back mode:
+ Emergency call back mode will be checked by reading system properties
+ when necessary: SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)
+ */
+ setInEmergency(PhoneNumberUtils.isEmergencyNumber(phoneNumber));
+ if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency());
+ } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
+ updateLocationMode();
+ if (DEBUG) Log.d(TAG, "location enabled :" + getLocationEnabled());
+ }
+ }
+ };
+
/**
* The notification that is shown when a network-initiated notification
- * (and verification) event is received.
+ * (and verification) event is received.
* <p>
* This is lazily created, so use {@link #setNINotification()}.
*/
private Notification mNiNotification;
-
- public GpsNetInitiatedHandler(Context context) {
+
+ public GpsNetInitiatedHandler(Context context,
+ INetInitiatedListener netInitiatedListener,
+ boolean isSuplEsEnabled) {
mContext = context;
+
+ if (netInitiatedListener == null) {
+ throw new IllegalArgumentException("netInitiatedListener is null");
+ } else {
+ mNetInitiatedListener = netInitiatedListener;
+ }
+
+ setSuplEsEnabled(isSuplEsEnabled);
mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
+ updateLocationMode();
+ mTelephonyManager =
+ (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+
+ mPhoneStateListener = new PhoneStateListener() {
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ if (DEBUG) Log.d(TAG, "onCallStateChanged(): state is "+ state);
+ // listening for emergency call ends
+ if (state == TelephonyManager.CALL_STATE_IDLE) {
+ setInEmergency(false);
+ }
+ }
+ };
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
+ intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
+ mContext.registerReceiver(mBroadcastReciever, intentFilter);
}
-
- // Handles NI events from HAL
- public void handleNiNotification(GpsNiNotification notif)
- {
- if (DEBUG) Log.d(TAG, "handleNiNotification" + " notificationId: " + notif.notificationId
- + " requestorId: " + notif.requestorId + " text: " + notif.text);
- // Notify and verify with immediate pop-up
- if (notif.needNotify && notif.needVerify && mPopupImmediately)
- {
- // Popup the dialog box now
- openNiDialog(notif);
- }
+ public void setSuplEsEnabled(boolean isEnabled) {
+ mIsSuplEsEnabled = isEnabled;
+ }
- // Notify only, or delayed pop-up (change mPopupImmediately to FALSE)
- if (notif.needNotify && !notif.needVerify ||
- notif.needNotify && notif.needVerify && !mPopupImmediately)
- {
- // Show the notification
+ public boolean getSuplEsEnabled() {
+ return mIsSuplEsEnabled;
+ }
- // if mPopupImmediately == FALSE and needVerify == TRUE, a dialog will be opened
- // when the user opens the notification message
+ /**
+ * Updates Location enabler based on location setting.
+ */
+ public void updateLocationMode() {
+ mIsLocationEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+ }
- setNiNotification(notif);
- }
+ /**
+ * Checks if user agreed to use location.
+ */
+ public boolean getLocationEnabled() {
+ return mIsLocationEnabled;
+ }
- // ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify; 3. privacy override.
- if ( notif.needNotify && !notif.needVerify ||
- !notif.needNotify && !notif.needVerify ||
- notif.privacyOverride)
- {
- mLocationManager.sendNiResponse(notif.notificationId, GPS_NI_RESPONSE_ACCEPT);
+ // Note: Currently, there are two mechanisms involved to determine if a
+ // phone is in emergency mode:
+ // 1. If the user is making an emergency call, this is provided by activly
+ // monitoring the outgoing phone number;
+ // 2. If the device is in a emergency callback state, this is provided by
+ // system properties.
+ // If either one of above exists, the phone is considered in an emergency
+ // mode. Because of this complexity, we need to be careful about how to set
+ // and clear the emergency state.
+ public void setInEmergency(boolean isInEmergency) {
+ mIsInEmergency = isInEmergency;
+ }
+
+ public boolean getInEmergency() {
+ boolean isInEmergencyCallback = Boolean.parseBoolean(
+ SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE));
+ return mIsInEmergency || isInEmergencyCallback;
+ }
+
+
+ // Handles NI events from HAL
+ public void handleNiNotification(GpsNiNotification notif) {
+ if (DEBUG) Log.d(TAG, "in handleNiNotification () :"
+ + " notificationId: " + notif.notificationId
+ + " requestorId: " + notif.requestorId
+ + " text: " + notif.text
+ + " mIsSuplEsEnabled" + getSuplEsEnabled()
+ + " mIsLocationEnabled" + getLocationEnabled());
+
+ if (getSuplEsEnabled()) {
+ handleNiInEs(notif);
+ } else {
+ handleNi(notif);
}
//////////////////////////////////////////////////////////////////////////
@@ -177,6 +280,78 @@ public class GpsNetInitiatedHandler {
//
}
+ // handle NI form HAL when SUPL_ES is disabled.
+ private void handleNi(GpsNiNotification notif) {
+ if (DEBUG) Log.d(TAG, "in handleNi () :"
+ + " needNotify: " + notif.needNotify
+ + " needVerify: " + notif.needVerify
+ + " privacyOverride: " + notif.privacyOverride
+ + " mPopupImmediately: " + mPopupImmediately
+ + " mInEmergency: " + getInEmergency());
+
+ if (!getLocationEnabled() && !getInEmergency()) {
+ // Location is currently disabled, ignore all NI requests.
+ try {
+ mNetInitiatedListener.sendNiResponse(notif.notificationId,
+ GPS_NI_RESPONSE_IGNORE);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in sendNiResponse");
+ }
+ }
+ if (notif.needNotify) {
+ // If NI does not need verify or the dialog is not requested
+ // to pop up immediately, the dialog box will not pop up.
+ if (notif.needVerify && mPopupImmediately) {
+ // Popup the dialog box now
+ openNiDialog(notif);
+ } else {
+ // Show the notification
+ setNiNotification(notif);
+ }
+ }
+ // ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify;
+ // 3. privacy override.
+ if (!notif.needVerify || notif.privacyOverride) {
+ try {
+ mNetInitiatedListener.sendNiResponse(notif.notificationId,
+ GPS_NI_RESPONSE_ACCEPT);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in sendNiResponse");
+ }
+ }
+ }
+
+ // handle NI from HAL when the SUPL_ES is enabled
+ private void handleNiInEs(GpsNiNotification notif) {
+
+ if (DEBUG) Log.d(TAG, "in handleNiInEs () :"
+ + " niType: " + notif.niType
+ + " notificationId: " + notif.notificationId);
+
+ // UE is in emergency mode when in emergency call mode or in emergency call back mode
+ /*
+ 1. When SUPL ES bit is off and UE is not in emergency mode:
+ Call handleNi() to do legacy behaviour.
+ 2. When SUPL ES bit is on and UE is in emergency mode:
+ Call handleNi() to do acceptance behaviour.
+ 3. When SUPL ES bit is off but UE is in emergency mode:
+ Ignore the emergency SUPL INIT.
+ 4. When SUPL ES bit is on but UE is not in emergency mode:
+ Ignore the emergency SUPL INIT.
+ */
+ boolean isNiTypeES = (notif.niType == GPS_NI_TYPE_EMERGENCY_SUPL);
+ if (isNiTypeES != getInEmergency()) {
+ try {
+ mNetInitiatedListener.sendNiResponse(notif.notificationId,
+ GPS_NI_RESPONSE_IGNORE);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in sendNiResponse");
+ }
+ } else {
+ handleNi(notif);
+ }
+ }
+
// Sets the NI notification.
private synchronized void setNiNotification(GpsNiNotification notif) {
NotificationManager notificationManager = (NotificationManager) mContext
@@ -203,14 +378,16 @@ public class GpsNetInitiatedHandler {
mNiNotification.defaults |= Notification.DEFAULT_SOUND;
} else {
mNiNotification.defaults &= ~Notification.DEFAULT_SOUND;
- }
+ }
mNiNotification.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_AUTO_CANCEL;
mNiNotification.tickerText = getNotifTicker(notif, mContext);
// if not to popup dialog immediately, pending intent will open the dialog
Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
- PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ mNiNotification.color = mContext.getResources().getColor(
+ com.android.internal.R.color.system_notification_accent_color);
mNiNotification.setLatestEventInfo(mContext, title, message, pi);
notificationManager.notifyAsUser(null, notif.notificationId, mNiNotification,
@@ -229,7 +406,7 @@ public class GpsNetInitiatedHandler {
mContext.startActivity(intent);
}
- // Construct the intent for bringing up the dialog activity, which shows the
+ // Construct the intent for bringing up the dialog activity, which shows the
// notification and takes user input
private Intent getDlgIntent(GpsNiNotification notif)
{
@@ -238,7 +415,7 @@ public class GpsNetInitiatedHandler {
String message = getDialogMessage(notif, mContext);
// directly bring up the NI activity
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setClass(mContext, com.android.internal.app.NetInitiatedActivity.class);
// put data in the intent
@@ -408,7 +585,7 @@ public class GpsNetInitiatedHandler {
decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
decodeString(notif.text, mIsHexInput, notif.textEncoding));
return message;
- }
+ }
// change this to configure dialog display (for verification)
static public String getDialogTitle(GpsNiNotification notif, Context context)
diff --git a/location/lib/java/com/android/location/provider/ActivityChangedEvent.java b/location/lib/java/com/android/location/provider/ActivityChangedEvent.java
new file mode 100644
index 0000000..c7dfc88
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/ActivityChangedEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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.location.provider;
+
+import android.annotation.NonNull;
+
+import java.security.InvalidParameterException;
+import java.util.List;
+
+/**
+ * A class representing an event for Activity changes.
+ */
+public class ActivityChangedEvent {
+ private final List<ActivityRecognitionEvent> mActivityRecognitionEvents;
+
+ public ActivityChangedEvent(List<ActivityRecognitionEvent> activityRecognitionEvents) {
+ if (activityRecognitionEvents == null) {
+ throw new InvalidParameterException(
+ "Parameter 'activityRecognitionEvents' must not be null.");
+ }
+
+ mActivityRecognitionEvents = activityRecognitionEvents;
+ }
+
+ @NonNull
+ public Iterable<ActivityRecognitionEvent> getActivityRecognitionEvents() {
+ return mActivityRecognitionEvents;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("[ ActivityChangedEvent:");
+
+ for (ActivityRecognitionEvent event : mActivityRecognitionEvents) {
+ builder.append("\n ");
+ builder.append(event.toString());
+ }
+ builder.append("\n]");
+
+ return builder.toString();
+ }
+}
diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java b/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java
new file mode 100644
index 0000000..a39cff2
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/ActivityRecognitionEvent.java
@@ -0,0 +1,70 @@
+/*
+ * 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.location.provider;
+
+/**
+ * A class that represents an Activity Recognition Event.
+ */
+public class ActivityRecognitionEvent {
+ private final String mActivity;
+ private final int mEventType;
+ private final long mTimestampNs;
+
+ public ActivityRecognitionEvent(String activity, int eventType, long timestampNs) {
+ mActivity = activity;
+ mEventType = eventType;
+ mTimestampNs = timestampNs;
+ }
+
+ public String getActivity() {
+ return mActivity;
+ }
+
+ public int getEventType() {
+ return mEventType;
+ }
+
+ public long getTimestampNs() {
+ return mTimestampNs;
+ }
+
+ @Override
+ public String toString() {
+ String eventString;
+ switch (mEventType) {
+ case ActivityRecognitionProvider.EVENT_TYPE_ENTER:
+ eventString = "Enter";
+ break;
+ case ActivityRecognitionProvider.EVENT_TYPE_EXIT:
+ eventString = "Exit";
+ break;
+ case ActivityRecognitionProvider.EVENT_TYPE_FLUSH_COMPLETE:
+ eventString = "FlushComplete";
+ break;
+ default:
+ eventString = "<Invalid>";
+ break;
+ }
+
+ return String.format(
+ "Activity='%s', EventType=%s(%s), TimestampNs=%s",
+ mActivity,
+ eventString,
+ mEventType,
+ mTimestampNs);
+ }
+}
diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java
new file mode 100644
index 0000000..da33464
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java
@@ -0,0 +1,134 @@
+/*
+ * 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.location.provider;
+
+import com.android.internal.util.Preconditions;
+
+import android.hardware.location.IActivityRecognitionHardware;
+import android.hardware.location.IActivityRecognitionHardwareSink;
+import android.os.RemoteException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * A class that exposes {@link IActivityRecognitionHardware} functionality to unbundled services.
+ */
+public final class ActivityRecognitionProvider {
+ private final IActivityRecognitionHardware mService;
+ private final HashSet<Sink> mSinkSet = new HashSet<Sink>();
+ private final SinkTransport mSinkTransport = new SinkTransport();
+
+ // the following constants must remain in sync with activity_recognition.h
+
+ public static final String ACTIVITY_IN_VEHICLE = "android.activity_recognition.in_vehicle";
+ public static final String ACTIVITY_ON_BICYCLE = "android.activity_recognition.on_bicycle";
+ public static final String ACTIVITY_WALKING = "android.activity_recognition.walking";
+ public static final String ACTIVITY_RUNNING = "android.activity_recognition.running";
+ public static final String ACTIVITY_STILL = "android.activity_recognition.still";
+ public static final String ACTIVITY_TILTING = "android.activity_recognition.tilting";
+
+ public static final int EVENT_TYPE_FLUSH_COMPLETE = 0;
+ public static final int EVENT_TYPE_ENTER = 1;
+ public static final int EVENT_TYPE_EXIT = 2;
+
+ // end constants activity_recognition.h
+
+ /**
+ * Used to receive Activity-Recognition events.
+ */
+ public interface Sink {
+ void onActivityChanged(ActivityChangedEvent event);
+ }
+
+ public ActivityRecognitionProvider(IActivityRecognitionHardware service)
+ throws RemoteException {
+ Preconditions.checkNotNull(service);
+ mService = service;
+ mService.registerSink(mSinkTransport);
+ }
+
+ public String[] getSupportedActivities() throws RemoteException {
+ return mService.getSupportedActivities();
+ }
+
+ public boolean isActivitySupported(String activity) throws RemoteException {
+ return mService.isActivitySupported(activity);
+ }
+
+ public void registerSink(Sink sink) {
+ Preconditions.checkNotNull(sink);
+ synchronized (mSinkSet) {
+ mSinkSet.add(sink);
+ }
+ }
+
+ // TODO: if this functionality is exposed to 3rd party developers, handle unregistration (here
+ // and in the service) of all sinks while failing to disable all events
+ public void unregisterSink(Sink sink) {
+ Preconditions.checkNotNull(sink);
+ synchronized (mSinkSet) {
+ mSinkSet.remove(sink);
+ }
+ }
+
+ public boolean enableActivityEvent(String activity, int eventType, long reportLatencyNs)
+ throws RemoteException {
+ return mService.enableActivityEvent(activity, eventType, reportLatencyNs);
+ }
+
+ public boolean disableActivityEvent(String activity, int eventType) throws RemoteException {
+ return mService.disableActivityEvent(activity, eventType);
+ }
+
+ public boolean flush() throws RemoteException {
+ return mService.flush();
+ }
+
+ private final class SinkTransport extends IActivityRecognitionHardwareSink.Stub {
+ @Override
+ public void onActivityChanged(
+ android.hardware.location.ActivityChangedEvent activityChangedEvent) {
+ Collection<Sink> sinks;
+ synchronized (mSinkSet) {
+ if (mSinkSet.isEmpty()) {
+ return;
+ }
+
+ sinks = new ArrayList<Sink>(mSinkSet);
+ }
+
+ // translate the event from platform internal and GmsCore types
+ ArrayList<ActivityRecognitionEvent> gmsEvents =
+ new ArrayList<ActivityRecognitionEvent>();
+ for (android.hardware.location.ActivityRecognitionEvent event
+ : activityChangedEvent.getActivityRecognitionEvents()) {
+ ActivityRecognitionEvent gmsEvent = new ActivityRecognitionEvent(
+ event.getActivity(),
+ event.getEventType(),
+ event.getTimestampNs());
+ gmsEvents.add(gmsEvent);
+ }
+ ActivityChangedEvent gmsEvent = new ActivityChangedEvent(gmsEvents);
+
+ for (Sink sink : sinks) {
+ sink.onActivityChanged(gmsEvent);
+ }
+ }
+ }
+}
diff --git a/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java
new file mode 100644
index 0000000..03dd042
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProviderWatcher.java
@@ -0,0 +1,86 @@
+/*
+ * 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.location.provider;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.location.IActivityRecognitionHardware;
+import android.hardware.location.IActivityRecognitionHardwareWatcher;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * A watcher class for Activity-Recognition instances.
+ */
+public class ActivityRecognitionProviderWatcher {
+ private static final String TAG = "ActivityRecognitionProviderWatcher";
+
+ private static ActivityRecognitionProviderWatcher sWatcher;
+ private static final Object sWatcherLock = new Object();
+
+ private ActivityRecognitionProvider mActivityRecognitionProvider;
+
+ private ActivityRecognitionProviderWatcher() {}
+
+ public static ActivityRecognitionProviderWatcher getInstance() {
+ synchronized (sWatcherLock) {
+ if (sWatcher == null) {
+ sWatcher = new ActivityRecognitionProviderWatcher();
+ }
+ return sWatcher;
+ }
+ }
+
+ private IActivityRecognitionHardwareWatcher.Stub mWatcherStub =
+ new IActivityRecognitionHardwareWatcher.Stub() {
+ @Override
+ public void onInstanceChanged(IActivityRecognitionHardware instance) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ Log.d(TAG, "Ignoring calls from non-system server. Uid: " + callingUid);
+ return;
+ }
+
+ try {
+ mActivityRecognitionProvider = new ActivityRecognitionProvider(instance);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error creating Hardware Activity-Recognition", e);
+ }
+ }
+ };
+
+ /**
+ * Gets the binder needed to interact with proxy provider in the platform.
+ */
+ @NonNull
+ public IBinder getBinder() {
+ return mWatcherStub;
+ }
+
+ /**
+ * Gets an object that supports the functionality of {@link ActivityRecognitionProvider}.
+ *
+ * @return Non-null value if the functionality is supported by the platform, false otherwise.
+ */
+ @Nullable
+ public ActivityRecognitionProvider getActivityRecognitionProvider() {
+ return mActivityRecognitionProvider;
+ }
+}
diff --git a/location/lib/java/com/android/location/provider/GeofenceProvider.java b/location/lib/java/com/android/location/provider/GeofenceProvider.java
index 2618f34..fafaa84 100644
--- a/location/lib/java/com/android/location/provider/GeofenceProvider.java
+++ b/location/lib/java/com/android/location/provider/GeofenceProvider.java
@@ -21,9 +21,6 @@ import android.hardware.location.IGeofenceHardware;
import android.os.IBinder;
import android.location.IGeofenceProvider;
-import android.util.Log;
-
-import java.lang.Long;
/**
* Base class for geofence providers implemented as unbundled services.
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 150c289..d717f40 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -24,7 +24,6 @@ import android.content.Context;
import android.location.ILocationManager;
import android.location.Location;
import android.location.LocationManager;
-import android.location.LocationRequest;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;