summaryrefslogtreecommitdiffstats
path: root/location
diff options
context:
space:
mode:
Diffstat (limited to 'location')
-rw-r--r--location/Android.mk2
-rw-r--r--location/java/android/location/FusedBatchOptions.aidl19
-rw-r--r--location/java/android/location/FusedBatchOptions.java136
-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/IFusedGeofenceHardware.aidl93
-rw-r--r--location/java/android/location/IFusedProvider.aidl32
-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.java107
-rw-r--r--location/java/android/location/LocationRequest.java66
-rw-r--r--location/java/android/location/SettingInjectorService.java220
-rw-r--r--location/java/android/location/package.html30
-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/FusedLocationHardware.java280
-rw-r--r--location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java30
-rw-r--r--location/lib/java/com/android/location/provider/FusedProvider.java57
-rw-r--r--location/lib/java/com/android/location/provider/GeofenceProvider.java3
-rw-r--r--location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java106
-rw-r--r--location/lib/java/com/android/location/provider/LocationProviderBase.java4
34 files changed, 4472 insertions, 90 deletions
diff --git a/location/Android.mk b/location/Android.mk
index 12db2f7..feeb8ce 100644
--- a/location/Android.mk
+++ b/location/Android.mk
@@ -14,6 +14,4 @@
LOCAL_PATH := $(call my-dir)
-ifeq ($(TARGET_BUILD_APPS),)
include $(call all-makefiles-under, $(LOCAL_PATH))
-endif
diff --git a/location/java/android/location/FusedBatchOptions.aidl b/location/java/android/location/FusedBatchOptions.aidl
new file mode 100644
index 0000000..94cb6e1
--- /dev/null
+++ b/location/java/android/location/FusedBatchOptions.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013, 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 FusedBatchOptions; \ No newline at end of file
diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java
new file mode 100644
index 0000000..5600aeb
--- /dev/null
+++ b/location/java/android/location/FusedBatchOptions.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A data class representing a set of options to configure batching sessions.
+ * @hide
+ */
+public class FusedBatchOptions implements Parcelable {
+ private volatile long mPeriodInNS = 0;
+ private volatile int mSourcesToUse = 0;
+ private volatile int mFlags = 0;
+
+ // the default value is set to request fixes at no cost
+ private volatile double mMaxPowerAllocationInMW = 0;
+
+ /*
+ * Getters and setters for properties needed to hold the options.
+ */
+ public void setMaxPowerAllocationInMW(double value) {
+ mMaxPowerAllocationInMW = value;
+ }
+
+ public double getMaxPowerAllocationInMW() {
+ return mMaxPowerAllocationInMW;
+ }
+
+ public void setPeriodInNS(long value) {
+ mPeriodInNS = value;
+ }
+
+ public long getPeriodInNS() {
+ return mPeriodInNS;
+ }
+
+ public void setSourceToUse(int source) {
+ mSourcesToUse |= source;
+ }
+
+ public void resetSourceToUse(int source) {
+ mSourcesToUse &= ~source;
+ }
+
+ public boolean isSourceToUseSet(int source) {
+ return (mSourcesToUse & source) != 0;
+ }
+
+ public int getSourcesToUse() {
+ return mSourcesToUse;
+ }
+
+ public void setFlag(int flag) {
+ mFlags |= flag;
+ }
+
+ public void resetFlag(int flag) {
+ mFlags &= ~flag;
+ }
+
+ public boolean isFlagSet(int flag) {
+ return (mFlags & flag) != 0;
+ }
+
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Definition of enum flag sets needed by this class.
+ * Such values need to be kept in sync with the ones in fused_location.h
+ */
+ public static final class SourceTechnologies {
+ public static int GNSS = 1<<0;
+ public static int WIFI = 1<<1;
+ public static int SENSORS = 1<<2;
+ public static int CELL = 1<<3;
+ public static int BLUETOOTH = 1<<4;
+ }
+
+ public static final class BatchFlags {
+ // 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;
+ }
+
+ /*
+ * Method definitions to support Parcelable operations.
+ */
+ public static final Parcelable.Creator<FusedBatchOptions> CREATOR =
+ new Parcelable.Creator<FusedBatchOptions>() {
+ @Override
+ public FusedBatchOptions createFromParcel(Parcel parcel) {
+ FusedBatchOptions options = new FusedBatchOptions();
+ options.setMaxPowerAllocationInMW(parcel.readDouble());
+ options.setPeriodInNS(parcel.readLong());
+ options.setSourceToUse(parcel.readInt());
+ options.setFlag(parcel.readInt());
+ return options;
+ }
+
+ @Override
+ public FusedBatchOptions[] newArray(int size) {
+ return new FusedBatchOptions[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeDouble(mMaxPowerAllocationInMW);
+ parcel.writeLong(mPeriodInNS);
+ parcel.writeInt(mSourcesToUse);
+ parcel.writeInt(mFlags);
+ }
+}
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/IFusedGeofenceHardware.aidl b/location/java/android/location/IFusedGeofenceHardware.aidl
new file mode 100644
index 0000000..d8c3585
--- /dev/null
+++ b/location/java/android/location/IFusedGeofenceHardware.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013, 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/license/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.hardware.location.GeofenceHardwareRequestParcelable;
+
+/**
+ * Fused Geofence Hardware interface.
+ *
+ * <p>This interface is the basic set of supported functionality by Fused Hardware modules that offer
+ * Geofencing capabilities.
+ *
+ * All operations are asynchronous and the status codes can be obtained via a set of callbacks.
+ *
+ * @hide
+ */
+interface IFusedGeofenceHardware {
+ /**
+ * Flags if the interface functionality is supported by the platform.
+ *
+ * @return true if the functionality is supported, false otherwise.
+ */
+ boolean isSupported();
+
+ /**
+ * Adds a given list of geofences to the system.
+ *
+ * @param geofenceRequestsArray The list of geofences to add.
+ */
+ void addGeofences(in GeofenceHardwareRequestParcelable[] geofenceRequestsArray);
+
+ /**
+ * Removes a give list of geofences from the system.
+ *
+ * @param geofences The list of geofences to remove.
+ */
+ void removeGeofences(in int[] geofenceIds);
+
+ /**
+ * Pauses monitoring a particular geofence.
+ *
+ * @param geofenceId The geofence to pause monitoring.
+ */
+ void pauseMonitoringGeofence(in int geofenceId);
+
+ /**
+ * Resumes monitoring a particular geofence.
+ *
+ * @param geofenceid The geofence to resume monitoring.
+ * @param transitionsToMonitor The transitions to monitor upon resume.
+ *
+ * Remarks: keep naming of geofence request options consistent with the naming used in
+ * GeofenceHardwareRequest
+ */
+ void resumeMonitoringGeofence(in int geofenceId, in int monitorTransitions);
+
+ /**
+ * Modifies the request options if a geofence that is already known by the
+ * system.
+ *
+ * @param geofenceId The geofence to modify.
+ * @param lastTransition The last known transition state of
+ * the geofence.
+ * @param monitorTransitions The set of transitions to monitor.
+ * @param notificationResponsiveness The notification responsivness needed.
+ * @param unknownTimer The time span associated with the.
+ * @param sourcesToUse The source technologies to use.
+ *
+ * Remarks: keep the options as separate fields to be able to leverage the class
+ * GeofenceHardwareRequest without any changes
+ */
+ void modifyGeofenceOptions(
+ in int geofenceId,
+ in int lastTransition,
+ in int monitorTransitions,
+ in int notificationResponsiveness,
+ in int unknownTimer,
+ in int sourcesToUse);
+}
diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl
new file mode 100644
index 0000000..8870d2a
--- /dev/null
+++ b/location/java/android/location/IFusedProvider.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 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.hardware.location.IFusedLocationHardware;
+
+/**
+ * Interface definition for Location providers that require FLP services.
+ * @hide
+ */
+interface IFusedProvider {
+ /**
+ * Provides access to a FusedLocationHardware instance needed for the provider to work.
+ *
+ * @param instance The FusedLocationHardware available for the provider to use.
+ */
+ void onFusedLocationHardwareChange(in IFusedLocationHardware instance);
+} \ No newline at end of file
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 989178a..ed408e0 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 =
@@ -152,12 +154,25 @@ public class LocationManager {
/**
* Broadcast intent action when the configured location providers
- * change.
+ * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the
+ * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION}
+ * instead.
*/
public static final String PROVIDERS_CHANGED_ACTION =
"android.location.PROVIDERS_CHANGED";
/**
+ * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes.
+ * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
+ * If you're interacting with {@link #isProviderEnabled(String)}, use
+ * {@link #PROVIDERS_CHANGED_ACTION} instead.
+ *
+ * In the future, there may be mode changes that do not result in
+ * {@link #PROVIDERS_CHANGED_ACTION} broadcasts.
+ */
+ public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
+
+ /**
* Broadcast intent action indicating that the GPS has either started or
* stopped receiving GPS fixes. An intent extra provides this state as a
* boolean, where {@code true} means that the GPS is actively receiving fixes.
@@ -177,6 +192,17 @@ public class LocationManager {
*/
public static final String EXTRA_GPS_ENABLED = "enabled";
+ /**
+ * Broadcast intent action indicating that a high power location requests
+ * has either started or stopped being active. The current state of
+ * active location requests should be read from AppOpsManager using
+ * {@code OP_MONITOR_HIGH_POWER_LOCATION}.
+ *
+ * @hide
+ */
+ public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =
+ "android.location.HIGH_POWER_REQUEST_CHANGE";
+
// Map from LocationListeners to their associated ListenerTransport objects
private HashMap<LocationListener,ListenerTransport> mListeners =
new HashMap<LocationListener,ListenerTransport>();
@@ -285,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) {
@@ -780,6 +809,7 @@ public class LocationManager {
*
* @hide
*/
+ @SystemApi
public void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper) {
checkListener(listener);
@@ -807,6 +837,7 @@ public class LocationManager {
*
* @hide
*/
+ @SystemApi
public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
checkPendingIntent(intent);
requestLocationUpdates(request, null, null, intent);
@@ -1075,11 +1106,20 @@ public class LocationManager {
* <p>If the user has enabled this provider in the Settings menu, true
* is returned otherwise false is returned
*
+ * <p>Callers should instead use
+ * {@link android.provider.Settings.Secure#LOCATION_MODE}
+ * 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#LOLLIPOP}, 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 is enabled
+ * @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);
@@ -1535,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}
@@ -1581,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);
@@ -1613,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 b607731..65e7ced 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -16,9 +16,11 @@
package android.location;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.os.WorkSource;
import android.util.TimeUtils;
@@ -83,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.
@@ -145,6 +148,8 @@ public final class LocationRequest implements Parcelable {
private long mExpireAt = Long.MAX_VALUE; // no expiry
private int mNumUpdates = Integer.MAX_VALUE; // no expiry
private float mSmallestDisplacement = 0.0f; // meters
+ private WorkSource mWorkSource = null;
+ private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
private String mProvider = LocationManager.FUSED_PROVIDER; // for deprecated APIs that explicitly request a provider
@@ -163,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;
@@ -188,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;
@@ -234,6 +241,8 @@ public final class LocationRequest implements Parcelable {
mNumUpdates = src.mNumUpdates;
mSmallestDisplacement = src.mSmallestDisplacement;
mProvider = src.mProvider;
+ mWorkSource = src.mWorkSource;
+ mHideFromAppOps = src.mHideFromAppOps;
}
/**
@@ -284,7 +293,7 @@ public final class LocationRequest implements Parcelable {
* no location sources are available), or you may receive them
* slower than requested. You may also receive them faster than
* requested (if other applications are requesting location at a
- * faster interval). The fastest rate that that you will receive
+ * faster interval). The fastest rate that you will receive
* updates can be controlled with {@link #setFastestInterval}.
*
* <p>Applications with only the coarse location permission may have their
@@ -471,6 +480,7 @@ public final class LocationRequest implements Parcelable {
/** @hide */
+ @SystemApi
public LocationRequest setProvider(String provider) {
checkProvider(provider);
mProvider = provider;
@@ -478,11 +488,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;
@@ -490,10 +502,57 @@ public final class LocationRequest implements Parcelable {
}
/** @hide */
+ @SystemApi
public float getSmallestDisplacement() {
return mSmallestDisplacement;
}
+ /**
+ * Sets the WorkSource to use for power blaming of this location request.
+ *
+ * <p>No permissions are required to make this call, however the LocationManager
+ * will throw a SecurityException when requesting location updates if the caller
+ * doesn't have the {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
+ *
+ * @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;
+ }
+
+ /**
+ * Sets whether or not this location request should be hidden from AppOps.
+ *
+ * <p>Hiding a location request from AppOps will remove user visibility in the UI as to this
+ * request's existence. It does not affect power blaming in the Battery page.
+ *
+ * <p>No permissions are required to make this call, however the LocationManager
+ * will throw a SecurityException when requesting location updates if the caller
+ * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.
+ *
+ * @param hideFromAppOps If true AppOps won't keep track of this location request.
+ * @see android.app.AppOpsManager
+ * @hide
+ */
+ @SystemApi
+ public void setHideFromAppOps(boolean hideFromAppOps) {
+ mHideFromAppOps = hideFromAppOps;
+ }
+
+ /** @hide */
+ @SystemApi
+ public boolean getHideFromAppOps() {
+ return mHideFromAppOps;
+ }
+
private static void checkInterval(long millis) {
if (millis < 0) {
throw new IllegalArgumentException("invalid interval: " + millis);
@@ -537,8 +596,11 @@ public final class LocationRequest implements Parcelable {
request.setExpireAt(in.readLong());
request.setNumUpdates(in.readInt());
request.setSmallestDisplacement(in.readFloat());
+ request.setHideFromAppOps(in.readInt() != 0);
String provider = in.readString();
if (provider != null) request.setProvider(provider);
+ WorkSource workSource = in.readParcelable(null);
+ if (workSource != null) request.setWorkSource(workSource);
return request;
}
@Override
@@ -560,7 +622,9 @@ public final class LocationRequest implements Parcelable {
parcel.writeLong(mExpireAt);
parcel.writeInt(mNumUpdates);
parcel.writeFloat(mSmallestDisplacement);
+ parcel.writeInt(mHideFromAppOps ? 1 : 0);
parcel.writeString(mProvider);
+ parcel.writeParcelable(mWorkSource, 0);
}
/** @hide */
diff --git a/location/java/android/location/SettingInjectorService.java b/location/java/android/location/SettingInjectorService.java
new file mode 100644
index 0000000..fcd2cde
--- /dev/null
+++ b/location/java/android/location/SettingInjectorService.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2013 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.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * 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
+ * apps. Location settings that apply only to one app should be shown within that app,
+ * rather than in the system settings.
+ * <p/>
+ * To add a preference to the list, a subclass of {@link SettingInjectorService} must be declared in
+ * the manifest as so:
+ *
+ * <pre>
+ * &lt;service android:name="com.example.android.injector.MyInjectorService" &gt;
+ * &lt;intent-filter&gt;
+ * &lt;action android:name="android.location.SettingInjectorService" /&gt;
+ * &lt;/intent-filter&gt;
+ *
+ * &lt;meta-data
+ * android:name="android.location.SettingInjectorService"
+ * android:resource="@xml/my_injected_location_setting" /&gt;
+ * &lt;/service&gt;
+ * </pre>
+ * The resource file specifies the static data for the setting:
+ * <pre>
+ * &lt;injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:title="@string/injected_setting_title"
+ * android:icon="@drawable/ic_acme_corp"
+ * android:settingsActivity="com.example.android.injector.MySettingActivity"
+ * /&gt;
+ * </pre>
+ * Here:
+ * <ul>
+ * <li>title: The {@link android.preference.Preference#getTitle()} value. The title should make
+ * it clear which apps are affected by the setting, typically by including the name of the
+ * developer. For example, "Acme Corp. ads preferences." </li>
+ *
+ * <li>icon: The {@link android.preference.Preference#getIcon()} value. Typically this will be a
+ * generic icon for the developer rather than the icon for an individual app.</li>
+ *
+ * <li>settingsActivity: the activity which is launched to allow the user to modify the setting
+ * value. The activity must be in the same package as the subclass of
+ * {@link SettingInjectorService}. The activity should use your own branding to help emphasize
+ * to the user that it is not part of the system settings.</li>
+ * </ul>
+ *
+ * To ensure a good user experience, your {@link android.app.Application#onCreate()},
+ * 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 only {@code settingsActivity} should display the value for
+ * each account.
+ */
+public abstract class SettingInjectorService extends Service {
+
+ private static final String TAG = "SettingInjectorService";
+
+ /**
+ * Intent action that must be declared in the manifest for the subclass. Used to start the
+ * service to read the dynamic status for the setting.
+ */
+ public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
+
+ /**
+ * Name of the meta-data tag used to specify the resource file that includes the settings
+ * attributes.
+ */
+ public static final String META_DATA_NAME = "android.location.SettingInjectorService";
+
+ /**
+ * Name of the XML tag that includes the attributes for the setting.
+ */
+ public static final String ATTRIBUTES_NAME = "injected-location-setting";
+
+ /**
+ * Intent action a client should broadcast when the value of one of its injected settings has
+ * changed, so that the setting can be updated in the UI.
+ */
+ public static final String ACTION_INJECTED_SETTING_CHANGED =
+ "android.location.InjectedSettingChanged";
+
+ /**
+ * Name of the bundle key for the string specifying whether the setting is currently enabled.
+ *
+ * @hide
+ */
+ public static final String ENABLED_KEY = "enabled";
+
+ /**
+ * Name of the intent key used to specify the messenger
+ *
+ * @hide
+ */
+ public static final String MESSENGER_KEY = "messenger";
+
+ private final String mName;
+
+ /**
+ * Constructor.
+ *
+ * @param name used to identify your subclass in log messages
+ */
+ public SettingInjectorService(String name) {
+ mName = name;
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public final void onStart(Intent intent, int startId) {
+ super.onStart(intent, startId);
+ }
+
+ @Override
+ public final int onStartCommand(Intent intent, int flags, int startId) {
+ onHandleIntent(intent);
+ stopSelf(startId);
+ return START_NOT_STICKY;
+ }
+
+ private void onHandleIntent(Intent intent) {
+
+ 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, true);
+ throw e;
+ }
+
+ sendStatus(intent, enabled);
+ }
+
+ /**
+ * Send the enabled values back to the caller via the messenger encoded in the
+ * intent.
+ */
+ private void sendStatus(Intent intent, boolean enabled) {
+ Message message = Message.obtain();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(ENABLED_KEY, enabled);
+ message.setData(bundle);
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, mName + ": received " + intent
+ + ", enabled=" + enabled + ", sending message: " + message);
+ }
+
+ Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY);
+ try {
+ messenger.send(message);
+ } catch (RemoteException e) {
+ Log.e(TAG, mName + ": sending dynamic status failed", e);
+ }
+ }
+
+ /**
+ * This method is no longer called, because status values are no longer shown for any injected
+ * setting.
+ *
+ * @return ignored
+ *
+ * @deprecated not called any more
+ */
+ @Deprecated
+ protected abstract String onGetSummary();
+
+ /**
+ * Returns the {@link android.preference.Preference#isEnabled()} value. Should not perform
+ * unpredictably-long operations such as network access--see the running-time comments in the
+ * class-level javadoc.
+ * <p/>
+ * Note that to prevent churn in the settings list, there is no support for dynamically choosing
+ * to hide a setting. Instead you should have this method return false, which will disable the
+ * setting and its link to your setting activity. One reason why you might choose to do this is
+ * if {@link android.provider.Settings.Secure#LOCATION_MODE} is {@link
+ * android.provider.Settings.Secure#LOCATION_MODE_OFF}.
+ * <p/>
+ * It is possible that the user may click on the setting before this method returns, so your
+ * settings activity must handle the case where it is invoked even though the setting is
+ * disabled. The simplest approach may be to simply call {@link android.app.Activity#finish()}
+ * when disabled.
+ *
+ * @return the {@link android.preference.Preference#isEnabled()} value
+ */
+ protected abstract boolean onGetEnabled();
+}
diff --git a/location/java/android/location/package.html b/location/java/android/location/package.html
index 81fcea4..2355e72 100644
--- a/location/java/android/location/package.html
+++ b/location/java/android/location/package.html
@@ -1,22 +1,20 @@
<html>
<body>
-<p>Contains the framework API classes that define Android location-based and related services.</p>
-<p class="note">
- <strong>Note:</strong> The Google Location Services API, part of Google Play
- Services, provides a more powerful, high-level framework that automates tasks such as
- location provider choice and power management. Location Services also provides new
- features such as activity detection that aren't available in the framework API. Developers who
- are using the framework API, as well as developers who are just now adding location-awareness
- to their apps, should strongly consider using the Location Services API.
-<br/>
- To learn more about the Location Services API, see
- <a href="{@docRoot}google/play-services/location.html">Location APIs</a>.
+<p>Contains the framework API classes that define Android location-based and
+ related services.</p>
+<p class="warning">
+<strong>This API is not the recommended method for accessing Android location.</strong><br>
+The
+<a href="{@docRoot}reference/com/google/android/gms/location/package-summary.html">Google Location Services API</a>,
+part of Google Play services, is the preferred way to add location-awareness to
+your app. It offers a simpler API, higher accuracy, low-power geofencing, and
+more. If you are currently using the android.location API, you are strongly
+encouraged to switch to the Google Location Services API as soon as
+possible.
+<br><br>
+To learn more about the Google Location Services API, see the
+<a href="{@docRoot}google/play-services/location.html">Location API overview</a>.
</p>
-
-<p>For more information about the framework API, see the
-<a href="{@docRoot}guide/topics/location/index.html">Location and Maps</a> guide.</p>
-{@more}
-
</body>
</html>
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/FusedLocationHardware.java b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
new file mode 100644
index 0000000..bc5a8a1
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2013 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.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+
+import android.location.Location;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class that exposes IFusedLocationHardware functionality to unbundled services.
+ */
+public final class FusedLocationHardware {
+ private final String TAG = "FusedLocationHardware";
+
+ private IFusedLocationHardware mLocationHardware;
+
+ // the list uses a copy-on-write pattern to update its contents
+ HashMap<FusedLocationHardwareSink, DispatcherHandler> mSinkList =
+ new HashMap<FusedLocationHardwareSink, DispatcherHandler>();
+
+ private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() {
+ @Override
+ public void onLocationAvailable(Location[] locations) {
+ dispatchLocations(locations);
+ }
+
+ @Override
+ public void onDiagnosticDataAvailable(String data) {
+ dispatchDiagnosticData(data);
+ }
+ };
+
+ /**
+ * @hide
+ */
+ public FusedLocationHardware(IFusedLocationHardware locationHardware) {
+ mLocationHardware = locationHardware;
+ }
+
+ /*
+ * Methods to provide a Facade for IFusedLocationHardware
+ */
+ public void registerSink(FusedLocationHardwareSink sink, Looper looper) {
+ if(sink == null || looper == null) {
+ throw new IllegalArgumentException("Parameter sink and looper cannot be null.");
+ }
+
+ boolean registerSink;
+ synchronized (mSinkList) {
+ // register only on first insertion
+ registerSink = mSinkList.size() == 0;
+ // guarantee uniqueness
+ if(mSinkList.containsKey(sink)) {
+ return;
+ }
+
+ HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
+ new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
+ newSinkList.put(sink, new DispatcherHandler(looper));
+ mSinkList = newSinkList;
+ }
+
+ if(registerSink) {
+ try {
+ mLocationHardware.registerSink(mInternalSink);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at registerSink");
+ }
+ }
+ }
+
+ public void unregisterSink(FusedLocationHardwareSink sink) {
+ if(sink == null) {
+ throw new IllegalArgumentException("Parameter sink cannot be null.");
+ }
+
+ boolean unregisterSink;
+ synchronized(mSinkList) {
+ if(!mSinkList.containsKey(sink)) {
+ //done
+ return;
+ }
+
+ HashMap<FusedLocationHardwareSink, DispatcherHandler> newSinkList =
+ new HashMap<FusedLocationHardwareSink, DispatcherHandler>(mSinkList);
+ newSinkList.remove(sink);
+ //unregister after the last sink
+ unregisterSink = newSinkList.size() == 0;
+
+ mSinkList = newSinkList;
+ }
+
+ if(unregisterSink) {
+ try {
+ mLocationHardware.unregisterSink(mInternalSink);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at unregisterSink");
+ }
+ }
+ }
+
+ public int getSupportedBatchSize() {
+ try {
+ return mLocationHardware.getSupportedBatchSize();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at getSupportedBatchSize");
+ return 0;
+ }
+ }
+
+ public void startBatching(int id, GmsFusedBatchOptions batchOptions) {
+ try {
+ mLocationHardware.startBatching(id, batchOptions.getParcelableOptions());
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at startBatching");
+ }
+ }
+
+ public void stopBatching(int id) {
+ try {
+ mLocationHardware.stopBatching(id);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at stopBatching");
+ }
+ }
+
+ public void updateBatchingOptions(int id, GmsFusedBatchOptions batchOptions) {
+ try {
+ mLocationHardware.updateBatchingOptions(id, batchOptions.getParcelableOptions());
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at updateBatchingOptions");
+ }
+ }
+
+ public void requestBatchOfLocations(int batchSizeRequest) {
+ try {
+ mLocationHardware.requestBatchOfLocations(batchSizeRequest);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at requestBatchOfLocations");
+ }
+ }
+
+ public boolean supportsDiagnosticDataInjection() {
+ try {
+ return mLocationHardware.supportsDiagnosticDataInjection();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at supportsDiagnisticDataInjection");
+ return false;
+ }
+ }
+
+ public void injectDiagnosticData(String data) {
+ try {
+ mLocationHardware.injectDiagnosticData(data);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at injectDiagnosticData");
+ }
+ }
+
+ public boolean supportsDeviceContextInjection() {
+ try {
+ return mLocationHardware.supportsDeviceContextInjection();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at supportsDeviceContextInjection");
+ return false;
+ }
+ }
+
+ public void injectDeviceContext(int deviceEnabledContext) {
+ try {
+ mLocationHardware.injectDeviceContext(deviceEnabledContext);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at injectDeviceContext");
+ }
+ }
+
+ /*
+ * Helper methods and classes
+ */
+ private class DispatcherHandler extends Handler {
+ public static final int DISPATCH_LOCATION = 1;
+ public static final int DISPATCH_DIAGNOSTIC_DATA = 2;
+
+ public DispatcherHandler(Looper looper) {
+ super(looper, null /*callback*/ , true /*async*/);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ MessageCommand command = (MessageCommand) message.obj;
+ switch(message.what) {
+ case DISPATCH_LOCATION:
+ command.dispatchLocation();
+ break;
+ case DISPATCH_DIAGNOSTIC_DATA:
+ command.dispatchDiagnosticData();
+ default:
+ Log.e(TAG, "Invalid dispatch message");
+ break;
+ }
+ }
+ }
+
+ private class MessageCommand {
+ private final FusedLocationHardwareSink mSink;
+ private final Location[] mLocations;
+ private final String mData;
+
+ public MessageCommand(
+ FusedLocationHardwareSink sink,
+ Location[] locations,
+ String data) {
+ mSink = sink;
+ mLocations = locations;
+ mData = data;
+ }
+
+ public void dispatchLocation() {
+ mSink.onLocationAvailable(mLocations);
+ }
+
+ public void dispatchDiagnosticData() {
+ mSink.onDiagnosticDataAvailable(mData);
+ }
+ }
+
+ private void dispatchLocations(Location[] locations) {
+ HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
+ synchronized (mSinkList) {
+ sinks = mSinkList;
+ }
+
+ for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
+ Message message = Message.obtain(
+ entry.getValue(),
+ DispatcherHandler.DISPATCH_LOCATION,
+ new MessageCommand(entry.getKey(), locations, null /*data*/));
+ message.sendToTarget();
+ }
+ }
+
+ private void dispatchDiagnosticData(String data) {
+ HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
+ synchronized(mSinkList) {
+ sinks = mSinkList;
+ }
+
+ for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
+ Message message = Message.obtain(
+ entry.getValue(),
+ DispatcherHandler.DISPATCH_DIAGNOSTIC_DATA,
+ new MessageCommand(entry.getKey(), null /*locations*/, data));
+ message.sendToTarget();
+ }
+ }
+}
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
new file mode 100644
index 0000000..2c39fa8
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 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.location.Location;
+
+/**
+ * Base class for sinks to interact with FusedLocationHardware.
+ */
+public abstract class FusedLocationHardwareSink {
+ /*
+ * Methods to provide a facade for IFusedLocationHardware
+ */
+ public abstract void onLocationAvailable(Location[] locations);
+ public abstract void onDiagnosticDataAvailable(String data);
+} \ No newline at end of file
diff --git a/location/lib/java/com/android/location/provider/FusedProvider.java b/location/lib/java/com/android/location/provider/FusedProvider.java
new file mode 100644
index 0000000..c966ade
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 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.hardware.location.IFusedLocationHardware;
+import android.location.IFusedProvider;
+import android.os.IBinder;
+
+/**
+ * Base class for Fused providers implemented as unbundled services.
+ *
+ * <p>Fused providers can be implemented as services and return the result of
+ * {@link com.android.location.provider.FusedProvider#getBinder()} in its getBinder() method.
+ *
+ * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
+ * API stable. See README.txt in the root of this package for more information.
+ */
+public abstract class FusedProvider {
+ private IFusedProvider.Stub mProvider = new IFusedProvider.Stub() {
+ @Override
+ public void onFusedLocationHardwareChange(IFusedLocationHardware instance) {
+ setFusedLocationHardware(new FusedLocationHardware(instance));
+ }
+ };
+
+ /**
+ * Gets the Binder associated with the provider.
+ * This is intended to be used for the onBind() method of a service that implements a fused
+ * service.
+ *
+ * @return The IBinder instance associated with the provider.
+ */
+ public IBinder getBinder() {
+ return mProvider;
+ }
+
+ /**
+ * Sets the FusedLocationHardware instance in the provider..
+ * @param value The instance to set. This can be null in cases where the service connection
+ * is disconnected.
+ */
+ public abstract void setFusedLocationHardware(FusedLocationHardware value);
+}
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/GmsFusedBatchOptions.java b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
new file mode 100644
index 0000000..fd3f402
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2013 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.location.FusedBatchOptions;
+
+/**
+ * Class that exposes FusedBatchOptions to the GmsCore .
+ */
+public class GmsFusedBatchOptions {
+ private FusedBatchOptions mOptions = new FusedBatchOptions();
+
+ /*
+ * Methods that provide a facade for properties in FusedBatchOptions.
+ */
+ public void setMaxPowerAllocationInMW(double value) {
+ mOptions.setMaxPowerAllocationInMW(value);
+ }
+
+ public double getMaxPowerAllocationInMW() {
+ return mOptions.getMaxPowerAllocationInMW();
+ }
+
+ public void setPeriodInNS(long value) {
+ mOptions.setPeriodInNS(value);
+ }
+
+ public long getPeriodInNS() {
+ return mOptions.getPeriodInNS();
+ }
+
+ public void setSourceToUse(int source) {
+ mOptions.setSourceToUse(source);
+ }
+
+ public void resetSourceToUse(int source) {
+ mOptions.resetSourceToUse(source);
+ }
+
+ public boolean isSourceToUseSet(int source) {
+ return mOptions.isSourceToUseSet(source);
+ }
+
+ public int getSourcesToUse() {
+ return mOptions.getSourcesToUse();
+ }
+
+ public void setFlag(int flag) {
+ mOptions.setFlag(flag);
+ }
+
+ public void resetFlag(int flag) {
+ mOptions.resetFlag(flag);
+ }
+
+ public boolean isFlagSet(int flag) {
+ return mOptions.isFlagSet(flag);
+ }
+
+ public int getFlags() {
+ return mOptions.getFlags();
+ }
+
+ /**
+ * Definition of enum flag sets needed by this class.
+ * Such values need to be kept in sync with the ones in fused_location.h
+ */
+
+ public static final class SourceTechnologies {
+ public static int GNSS = 1<<0;
+ public static int WIFI = 1<<1;
+ public static int SENSORS = 1<<2;
+ public static int CELL = 1<<3;
+ public static int BLUETOOTH = 1<<4;
+ }
+
+ public static final class BatchFlags {
+ public static int WAKEUP_ON_FIFO_FULL = 1<<0;
+ public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+ }
+
+ /*
+ * Method definitions for internal use.
+ */
+
+ /*
+ * @hide
+ */
+ public FusedBatchOptions getParcelableOptions() {
+ return mOptions;
+ }
+}
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 8a5a739..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;
@@ -35,6 +34,7 @@ import android.util.Log;
import com.android.internal.location.ILocationProvider;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.FastPrintWriter;
/**
* Base class for location providers implemented as unbundled services.
@@ -106,7 +106,7 @@ public abstract class LocationProviderBase {
}
@Override
public void dump(FileDescriptor fd, String[] args) {
- PrintWriter pw = new PrintWriter(new FileOutputStream(fd));
+ PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
onDump(fd, pw, args);
pw.flush();
}