From e61c0ceb8d0ade26d15e41e4c3ec42694ca64fa2 Mon Sep 17 00:00:00 2001 From: Shinru Han Date: Mon, 21 Dec 2020 21:03:42 +0800 Subject: [PATCH 1/2] Add CorrelationVector AIDL in JNI Test: on cuttlefish Bug: 171516016 Change-Id: I81529b27f00b62680d9e2a77e3d8a5ed2cb3c409 --- ...d_server_location_GnssLocationProvider.cpp | 6 +- services/core/jni/gnss/GnssMeasurement.cpp | 27 ++++-- services/core/jni/gnss/GnssMeasurement.h | 12 +-- .../core/jni/gnss/GnssMeasurementCallback.cpp | 85 ++++++++++++++++++- 4 files changed, 112 insertions(+), 18 deletions(-) diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 35aad3e268ed2..b2d6b15a4930d 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -2709,7 +2709,7 @@ static jboolean android_location_gnss_hal_GnssNative_is_measurement_supported(JN } static jboolean android_location_gnss_hal_GnssNative_start_measurement_collection( - JNIEnv* /* env */, jclass, jboolean enableFullTracking) { + JNIEnv* /* env */, jclass, jboolean enableFullTracking, jboolean enableCorrVecOutputs) { if (gnssMeasurementIface == nullptr) { ALOGE("%s: IGnssMeasurement interface not available.", __func__); return JNI_FALSE; @@ -2717,7 +2717,7 @@ static jboolean android_location_gnss_hal_GnssNative_start_measurement_collectio return gnssMeasurementIface->setCallback(std::make_unique( mCallbacksObj), - enableFullTracking); + enableFullTracking, enableCorrVecOutputs); } static jboolean android_location_gnss_hal_GnssNative_stop_measurement_collection(JNIEnv* env, @@ -3211,7 +3211,7 @@ static const JNINativeMethod sMeasurementMethods[] = { /* name, signature, funcPtr */ {"native_is_measurement_supported", "()Z", reinterpret_cast(android_location_gnss_hal_GnssNative_is_measurement_supported)}, - {"native_start_measurement_collection", "(Z)Z", + {"native_start_measurement_collection", "(ZZ)Z", reinterpret_cast( android_location_gnss_hal_GnssNative_start_measurement_collection)}, {"native_stop_measurement_collection", "()Z", diff --git a/services/core/jni/gnss/GnssMeasurement.cpp b/services/core/jni/gnss/GnssMeasurement.cpp index 2261c38fb185b..663d839ff1591 100644 --- a/services/core/jni/gnss/GnssMeasurement.cpp +++ b/services/core/jni/gnss/GnssMeasurement.cpp @@ -50,8 +50,9 @@ GnssMeasurement::GnssMeasurement(const sp& iGnssMeasu : mIGnssMeasurement(iGnssMeasurement) {} jboolean GnssMeasurement::setCallback(const std::unique_ptr& callback, - bool enableFullTracking) { - auto status = mIGnssMeasurement->setCallback(callback->getAidl(), enableFullTracking); + bool enableFullTracking, bool enableCorrVecOutputs) { + auto status = mIGnssMeasurement->setCallback(callback->getAidl(), enableFullTracking, + enableCorrVecOutputs); return checkAidlStatus(status, "IGnssMeasurement setCallback() failed."); } @@ -66,9 +67,12 @@ GnssMeasurement_V1_0::GnssMeasurement_V1_0(const sp& iGns : mIGnssMeasurement_V1_0(iGnssMeasurement) {} jboolean GnssMeasurement_V1_0::setCallback(const std::unique_ptr& callback, - bool enableFullTracking) { + bool enableFullTracking, bool enableCorrVecOutputs) { if (enableFullTracking == true) { - ALOGW("Full tracking is mode not supported in 1.0 GNSS HAL."); + ALOGW("Full tracking mode is not supported in 1.0 GNSS HAL."); + } + if (enableCorrVecOutputs == true) { + ALOGW("Correlation vector output is not supported in 1.0 GNSS HAL."); } auto status = mIGnssMeasurement_V1_0->setCallback(callback->getHidl()); if (!checkHidlReturn(status, "IGnssMeasurement setCallback() failed.")) { @@ -89,7 +93,10 @@ GnssMeasurement_V1_1::GnssMeasurement_V1_1(const sp& iGns : GnssMeasurement_V1_0{iGnssMeasurement}, mIGnssMeasurement_V1_1(iGnssMeasurement) {} jboolean GnssMeasurement_V1_1::setCallback(const std::unique_ptr& callback, - bool enableFullTracking) { + bool enableFullTracking, bool enableCorrVecOutputs) { + if (enableCorrVecOutputs == true) { + ALOGW("Correlation vector output is not supported in 1.1 GNSS HAL."); + } auto status = mIGnssMeasurement_V1_1->setCallback_1_1(callback->getHidl(), enableFullTracking); if (!checkHidlReturn(status, "IGnssMeasurement setCallback_V1_1() failed.")) { return JNI_FALSE; @@ -104,7 +111,10 @@ GnssMeasurement_V2_0::GnssMeasurement_V2_0(const sp& iGns : GnssMeasurement_V1_1{iGnssMeasurement}, mIGnssMeasurement_V2_0(iGnssMeasurement) {} jboolean GnssMeasurement_V2_0::setCallback(const std::unique_ptr& callback, - bool enableFullTracking) { + bool enableFullTracking, bool enableCorrVecOutputs) { + if (enableCorrVecOutputs == true) { + ALOGW("Correlation vector output is not supported in 2.0 GNSS HAL."); + } auto status = mIGnssMeasurement_V2_0->setCallback_2_0(callback->getHidl(), enableFullTracking); if (!checkHidlReturn(status, "IGnssMeasurement setCallback_2_0() failed.")) { return JNI_FALSE; @@ -119,7 +129,10 @@ GnssMeasurement_V2_1::GnssMeasurement_V2_1(const sp& iGns : GnssMeasurement_V2_0{iGnssMeasurement}, mIGnssMeasurement_V2_1(iGnssMeasurement) {} jboolean GnssMeasurement_V2_1::setCallback(const std::unique_ptr& callback, - bool enableFullTracking) { + bool enableFullTracking, bool enableCorrVecOutputs) { + if (enableCorrVecOutputs == true) { + ALOGW("Correlation vector output is not supported in 2.1 GNSS HAL."); + } auto status = mIGnssMeasurement_V2_1->setCallback_2_1(callback->getHidl(), enableFullTracking); if (!checkHidlReturn(status, "IGnssMeasurement setCallback_2_1() failed.")) { return JNI_FALSE; diff --git a/services/core/jni/gnss/GnssMeasurement.h b/services/core/jni/gnss/GnssMeasurement.h index e64336fb67ac7..f0752cd3ab5b2 100644 --- a/services/core/jni/gnss/GnssMeasurement.h +++ b/services/core/jni/gnss/GnssMeasurement.h @@ -38,7 +38,7 @@ class GnssMeasurementInterface { public: virtual ~GnssMeasurementInterface() {} virtual jboolean setCallback(const std::unique_ptr& callback, - bool enableFullTracking) = 0; + bool enableFullTracking, bool enableCorrVecOutputs) = 0; virtual jboolean close() = 0; }; @@ -46,7 +46,7 @@ class GnssMeasurement : public GnssMeasurementInterface { public: GnssMeasurement(const sp& iGnssMeasurement); jboolean setCallback(const std::unique_ptr& callback, - bool enableFullTracking) override; + bool enableFullTracking, bool enableCorrVecOutputs) override; jboolean close() override; private: @@ -58,7 +58,7 @@ public: GnssMeasurement_V1_0( const sp& iGnssMeasurement); jboolean setCallback(const std::unique_ptr& callback, - bool enableFullTracking) override; + bool enableFullTracking, bool enableCorrVecOutputs) override; jboolean close() override; private: @@ -70,7 +70,7 @@ public: GnssMeasurement_V1_1( const sp& iGnssMeasurement); jboolean setCallback(const std::unique_ptr& callback, - bool enableFullTracking) override; + bool enableFullTracking, bool enableCorrVecOutputs) override; private: const sp mIGnssMeasurement_V1_1; @@ -81,7 +81,7 @@ public: GnssMeasurement_V2_0( const sp& iGnssMeasurement); jboolean setCallback(const std::unique_ptr& callback, - bool enableFullTracking) override; + bool enableFullTracking, bool enableCorrVecOutputs) override; private: const sp mIGnssMeasurement_V2_0; @@ -92,7 +92,7 @@ public: GnssMeasurement_V2_1( const sp& iGnssMeasurement); jboolean setCallback(const std::unique_ptr& callback, - bool enableFullTracking) override; + bool enableFullTracking, bool enableCorrVecOutputs) override; private: const sp mIGnssMeasurement_V2_1; diff --git a/services/core/jni/gnss/GnssMeasurementCallback.cpp b/services/core/jni/gnss/GnssMeasurementCallback.cpp index 8cba77328248a..757381dff80af 100644 --- a/services/core/jni/gnss/GnssMeasurementCallback.cpp +++ b/services/core/jni/gnss/GnssMeasurementCallback.cpp @@ -21,21 +21,33 @@ namespace android::gnss { using binder::Status; +using hardware::gnss::CorrelationVector; using hardware::gnss::ElapsedRealtime; using hardware::gnss::GnssClock; using hardware::gnss::GnssData; using hardware::gnss::GnssMeasurement; using hardware::gnss::SatellitePvt; +jclass class_arrayList; +jclass class_clockInfo; +jclass class_correlationVectorBuilder; jclass class_gnssMeasurementsEvent; jclass class_gnssMeasurement; jclass class_gnssClock; -jclass class_satellitePvtBuilder; jclass class_positionEcef; +jclass class_satellitePvtBuilder; jclass class_velocityEcef; -jclass class_clockInfo; +jmethodID method_arrayListAdd; +jmethodID method_arrayListCtor; +jmethodID method_correlationVectorBuilderBuild; +jmethodID method_correlationVectorBuilderCtor; +jmethodID method_correlationVectorBuilderSetFrequencyOffsetMetersPerSecond; +jmethodID method_correlationVectorBuilderSetMagnitude; +jmethodID method_correlationVectorBuilderSetSamplingStartMeters; +jmethodID method_correlationVectorBuilderSetSamplingWidthMeters; jmethodID method_gnssMeasurementsEventCtor; +jmethodID method_gnssMeasurementsSetCorrelationVectors; jmethodID method_gnssMeasurementsSetSatellitePvt; jmethodID method_gnssClockCtor; jmethodID method_gnssMeasurementCtor; @@ -66,6 +78,9 @@ void GnssMeasurement_class_init_once(JNIEnv* env, jclass& clazz) { method_gnssMeasurementsSetSatellitePvt = env->GetMethodID(class_gnssMeasurement, "setSatellitePvt", "(Landroid/location/SatellitePvt;)V"); + method_gnssMeasurementsSetCorrelationVectors = + env->GetMethodID(class_gnssMeasurement, "setCorrelationVectors", + "(Ljava/util/Collection;)V"); jclass gnssClockClass = env->FindClass("android/location/GnssClock"); class_gnssClock = (jclass)env->NewGlobalRef(gnssClockClass); @@ -106,6 +121,31 @@ void GnssMeasurement_class_init_once(JNIEnv* env, jclass& clazz) { jclass clockInfoClass = env->FindClass("android/location/SatellitePvt$ClockInfo"); class_clockInfo = (jclass)env->NewGlobalRef(clockInfoClass); method_clockInfo = env->GetMethodID(class_clockInfo, "", "(DDD)V"); + + jclass correlationVectorBuilder = env->FindClass("android/location/CorrelationVector$Builder"); + class_correlationVectorBuilder = (jclass)env->NewGlobalRef(correlationVectorBuilder); + method_correlationVectorBuilderCtor = + env->GetMethodID(class_correlationVectorBuilder, "", "()V"); + method_correlationVectorBuilderSetMagnitude = + env->GetMethodID(class_correlationVectorBuilder, "setMagnitude", + "([I)Landroid/location/CorrelationVector$Builder;"); + method_correlationVectorBuilderSetFrequencyOffsetMetersPerSecond = + env->GetMethodID(class_correlationVectorBuilder, "setFrequencyOffsetMetersPerSecond", + "(I)Landroid/location/CorrelationVector$Builder;"); + method_correlationVectorBuilderSetSamplingStartMeters = + env->GetMethodID(class_correlationVectorBuilder, "setSamplingStartMeters", + "(D)Landroid/location/CorrelationVector$Builder;"); + method_correlationVectorBuilderSetSamplingWidthMeters = + env->GetMethodID(class_correlationVectorBuilder, "setSamplingWidthMeters", + "(D)Landroid/location/CorrelationVector$Builder;"); + method_correlationVectorBuilderBuild = + env->GetMethodID(class_correlationVectorBuilder, "build", + "()Landroid/location/CorrelationVector;"); + + jclass arrayListClass = env->FindClass("java/util/ArrayList"); + class_arrayList = (jclass)env->NewGlobalRef(arrayListClass); + method_arrayListCtor = env->GetMethodID(class_arrayList, "", "()V"); + method_arrayListAdd = env->GetMethodID(class_arrayList, "add", "(Ljava/lang/Object;)Z"); } void setMeasurementData(JNIEnv* env, jobject& callbacksObj, jobject clock, @@ -310,6 +350,47 @@ void GnssMeasurementCallbackAidl::translateSingleGnssMeasurement(JNIEnv* env, env->DeleteLocalRef(satellitePvtObject); } + if (measurement.flags & static_cast(GnssMeasurement::HAS_CORRELATION_VECTOR)) { + jobject correlationVectorList = env->NewObject(class_arrayList, method_arrayListCtor); + for (uint16_t i = 0; i < measurement.correlationVectors.size(); ++i) { + const CorrelationVector& correlationVector = measurement.correlationVectors[i]; + const std::vector& magnitudeVector = correlationVector.magnitude; + + jsize numMagnitude = magnitudeVector.size(); + jintArray magnitudeArray = env->NewIntArray(numMagnitude); + env->SetIntArrayRegion(magnitudeArray, 0, numMagnitude, + reinterpret_cast(magnitudeVector.data())); + + jobject correlationVectorBuilderObject = + env->NewObject(class_correlationVectorBuilder, + method_correlationVectorBuilderCtor); + env->CallObjectMethod(correlationVectorBuilderObject, + method_correlationVectorBuilderSetMagnitude, magnitudeArray); + env->CallObjectMethod(correlationVectorBuilderObject, + method_correlationVectorBuilderSetFrequencyOffsetMetersPerSecond, + correlationVector.frequencyOffsetMps); + env->CallObjectMethod(correlationVectorBuilderObject, + method_correlationVectorBuilderSetSamplingStartMeters, + correlationVector.samplingStartM); + env->CallObjectMethod(correlationVectorBuilderObject, + method_correlationVectorBuilderSetSamplingWidthMeters, + correlationVector.samplingWidthM); + jobject correlationVectorObject = + env->CallObjectMethod(correlationVectorBuilderObject, + method_correlationVectorBuilderBuild); + + env->CallBooleanMethod(correlationVectorList, method_arrayListAdd, + correlationVectorObject); + + env->DeleteLocalRef(magnitudeArray); + env->DeleteLocalRef(correlationVectorBuilderObject); + env->DeleteLocalRef(correlationVectorObject); + } + env->CallVoidMethod(object.get(), method_gnssMeasurementsSetCorrelationVectors, + correlationVectorList); + env->DeleteLocalRef(correlationVectorList); + } + jstring codeType = env->NewStringUTF(measurement.signalType.codeType.c_str()); SET(CodeType, codeType); env->DeleteLocalRef(codeType); From daffd228199ed35d890dae22b440ea1c66eadf4e Mon Sep 17 00:00:00 2001 From: Shinru Han Date: Mon, 21 Dec 2020 21:11:33 +0800 Subject: [PATCH 2/2] Add CorrelationVector AIDL (framework/base) Test: on cuttlefish Bug: 171516016 Change-Id: Ib214c52701e0d0139083e8e3bb3c5862d29da48a --- core/api/system-current.txt | 31 +++ core/api/test-current.txt | 2 + core/api/test-lint-baseline.txt | 2 + .../android/location/CorrelationVector.java | 228 ++++++++++++++++++ .../android/location/GnssCapabilities.java | 30 ++- .../android/location/GnssMeasurement.java | 83 +++++++ .../location/GnssMeasurementRequest.java | 50 +++- .../android/location/LocationManager.java | 4 +- .../location/gnss/GnssManagerService.java | 4 +- .../gnss/GnssMeasurementsProvider.java | 25 +- .../server/location/gnss/hal/GnssNative.java | 13 +- .../server/location/gnss/hal/FakeGnssHal.java | 6 +- 12 files changed, 456 insertions(+), 22 deletions(-) create mode 100644 location/java/android/location/CorrelationVector.java diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 730fce7c049a2..7f75ee312b6f4 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3975,6 +3975,25 @@ package android.location { method public void onLocationBatch(java.util.List); } + public final class CorrelationVector implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0) public int getFrequencyOffsetMetersPerSecond(); + method @NonNull public int[] getMagnitude(); + method @FloatRange(from=0.0f) public double getSamplingStartMeters(); + method @FloatRange(from=0.0f, fromInclusive=false) public double getSamplingWidthMeters(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class CorrelationVector.Builder { + ctor public CorrelationVector.Builder(); + method @NonNull public android.location.CorrelationVector build(); + method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@IntRange(from=0) int); + method @NonNull public android.location.CorrelationVector.Builder setMagnitude(@NonNull int[]); + method @NonNull public android.location.CorrelationVector.Builder setSamplingStartMeters(@FloatRange(from=0.0f) double); + method @NonNull public android.location.CorrelationVector.Builder setSamplingWidthMeters(@FloatRange(from=0.0f, fromInclusive=false) double); + } + public final class GnssCapabilities implements android.os.Parcelable { method public boolean hasGeofencing(); method public boolean hasLowPowerMode(); @@ -3983,6 +4002,7 @@ package android.location { method public boolean hasMeasurementCorrectionsLosSats(); method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane(); method public boolean hasMeasurementCorrectionsReflectingPlane(); + method public boolean hasMeasurementCorrelationVectors(); method @Deprecated public boolean hasNavMessages(); method @Deprecated public boolean hasSatelliteBlacklist(); method public boolean hasSatelliteBlocklist(); @@ -3996,12 +4016,15 @@ package android.location { method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsExcessPathLength(boolean); method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsLosSats(boolean); method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsReflectingPlane(boolean); + method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrelationVectors(boolean); method @NonNull public android.location.GnssCapabilities.Builder setHasSatelliteBlocklist(boolean); method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean); } public final class GnssMeasurement implements android.os.Parcelable { + method @Nullable public java.util.Collection getCorrelationVectors(); method @Nullable public android.location.SatellitePvt getSatellitePvt(); + method public boolean hasCorrelationVectors(); method public boolean hasSatellitePvt(); } @@ -4035,6 +4058,14 @@ package android.location { method @NonNull public android.location.GnssMeasurementCorrections.Builder setVerticalPositionUncertaintyMeters(@FloatRange(from=0.0f) double); } + public final class GnssMeasurementRequest implements android.os.Parcelable { + method public boolean isCorrelationVectorOutputsEnabled(); + } + + public static final class GnssMeasurementRequest.Builder { + method @NonNull public android.location.GnssMeasurementRequest.Builder setCorrelationVectorOutputsEnabled(boolean); + } + public final class GnssReflectingPlane implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters(); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 62c660cbcb6cd..6e1ce1b6891c6 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -929,6 +929,7 @@ package android.location { method @Deprecated public void resetCarrierPhase(); method @Deprecated public void resetCarrierPhaseUncertainty(); method public void resetCodeType(); + method public void resetCorrelationVectors(); method public void resetFullInterSignalBiasNanos(); method public void resetFullInterSignalBiasUncertaintyNanos(); method public void resetSatelliteInterSignalBiasNanos(); @@ -948,6 +949,7 @@ package android.location { method public void setCn0DbHz(double); method public void setCodeType(@NonNull String); method public void setConstellationType(int); + method public void setCorrelationVectors(@Nullable java.util.Collection); method public void setFullInterSignalBiasNanos(double); method public void setFullInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double); method public void setMultipathIndicator(int); diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 3bd88a47f30d6..216d340690833 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -468,6 +468,8 @@ GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double): GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float): GetterSetterNames: android.location.GnssMeasurement#setCodeType(String): + +GetterSetterNames: android.location.GnssMeasurement#setCorrelationVectors(java.util.Collection): GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double): diff --git a/location/java/android/location/CorrelationVector.java b/location/java/android/location/CorrelationVector.java new file mode 100644 index 0000000000000..eca35dd69362f --- /dev/null +++ b/location/java/android/location/CorrelationVector.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2020 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.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Contains info about the correlation output of incoming GNSS signal and a local copy of + * its corresponding spreading code at a given frequency offset. + * + * @hide + */ +@SystemApi +public final class CorrelationVector implements Parcelable { + + private final double mSamplingWidthMeters; + private final double mSamplingStartMeters; + private final int mFrequencyOffsetMetersPerSecond; + @NonNull private final int[] mMagnitude; + + /** + * Returns the space between correlation samples in meters. + */ + @FloatRange(from = 0.0f, fromInclusive = false) + public double getSamplingWidthMeters() { + return mSamplingWidthMeters; + } + + /** + * Returns the offset of the first sampling bin in meters. + * + *

The following sampling bins are located at positive offsets from this value as follows: + * samplingStartMeters, samplingStartMeters + samplingWidthMeters, ... , samplingStartMeters + + * (magnitude.size-1) * samplingWidthMeters. + * + */ + @FloatRange(from = 0.0f) + public double getSamplingStartMeters() { + return mSamplingStartMeters; + } + + /** + * Returns the frequency offset from reported pseudorange rate for this CorrelationVector. + */ + @IntRange(from = 0) + public int getFrequencyOffsetMetersPerSecond() { + return mFrequencyOffsetMetersPerSecond; + } + + /** + * Returns the data array representing normalized correlation magnitude values. + * + *

The data are normalized correlation magnitude values from -1 to 1, the reported value must + * be encoded as signed 16 bit integer where 1 is represented by 32767 and -1 is represented + * by -32768. + * + */ + @NonNull + public int[] getMagnitude() { + return mMagnitude.clone(); + } + + private CorrelationVector(Builder builder) { + Preconditions.checkNotNull(builder.mMagnitude, "Magnitude array must not be null"); + Preconditions.checkArgumentPositive(builder.mMagnitude.length, + "Magnitude array must have non-zero length"); + Preconditions.checkArgumentNonNegative(builder.mFrequencyOffsetMetersPerSecond, + "FrequencyOffsetMetersPerSecond must be non-negative (greater than or equal to 0)"); + Preconditions.checkArgument(builder.mSamplingWidthMeters > 0.0, + "SamplingWidthMeters must be positive (greater than 0)"); + Preconditions.checkArgument(builder.mSamplingStartMeters >= 0.0, + "SamplingStartMeters must be non-negative (greater than or equal to 0)"); + mMagnitude = builder.mMagnitude; + mFrequencyOffsetMetersPerSecond = builder.mFrequencyOffsetMetersPerSecond; + mSamplingWidthMeters = builder.mSamplingWidthMeters; + mSamplingStartMeters = builder.mSamplingStartMeters; + } + + private CorrelationVector(Parcel in) { + mSamplingWidthMeters = in.readDouble(); + mSamplingStartMeters = in.readDouble(); + mFrequencyOffsetMetersPerSecond = in.readInt(); + mMagnitude = new int[in.readInt()]; + in.readIntArray(mMagnitude); + } + + /* + * Method definitions to support Parcelable operations. + */ + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public CorrelationVector createFromParcel(Parcel parcel) { + return new CorrelationVector(parcel); + } + + @Override + public CorrelationVector[] newArray(int size) { + return new CorrelationVector[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @NonNull + @Override + public String toString() { + return "CorrelationVector{" + + "FrequencyOffsetMetersPerSecond=" + mFrequencyOffsetMetersPerSecond + + ", SamplingWidthMeters=" + mSamplingWidthMeters + + ", SamplingStartMeters=" + mSamplingStartMeters + + ", Magnitude=" + Arrays.toString(mMagnitude) + + '}'; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeDouble(mSamplingWidthMeters); + dest.writeDouble(mSamplingStartMeters); + dest.writeInt(mFrequencyOffsetMetersPerSecond); + dest.writeInt(mMagnitude.length); + dest.writeIntArray(mMagnitude); + } + + /** + * Returns true if this {@link CorrelationVector} is equivalent to the given object. + * Returns false otherwise. + */ + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (!(object instanceof CorrelationVector)) { + return false; + } + CorrelationVector c = (CorrelationVector) object; + return Arrays.equals(mMagnitude, c.getMagnitude()) + && Double.compare(mSamplingWidthMeters, c.getSamplingWidthMeters()) == 0 + && Double.compare(mSamplingStartMeters, c.getSamplingStartMeters()) == 0 + && Integer.compare(mFrequencyOffsetMetersPerSecond, + c.getFrequencyOffsetMetersPerSecond()) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(mSamplingWidthMeters, mSamplingStartMeters, + mFrequencyOffsetMetersPerSecond, Arrays.hashCode(mMagnitude)); + } + + /** + * Builder class for CorrelationVector. + */ + public static final class Builder { + + private double mSamplingWidthMeters; + private double mSamplingStartMeters; + private int mFrequencyOffsetMetersPerSecond; + @NonNull private int[] mMagnitude; + + /** Sets the space between correlation samples in meters. */ + @NonNull + public Builder setSamplingWidthMeters( + @FloatRange(from = 0.0f, fromInclusive = false) double samplingWidthMeters) { + mSamplingWidthMeters = samplingWidthMeters; + return this; + } + + /** Sets the offset of the first sampling bin in meters. */ + @NonNull + public Builder setSamplingStartMeters(@FloatRange(from = 0.0f) double samplingStartMeters) { + mSamplingStartMeters = samplingStartMeters; + return this; + } + + /** Sets the frequency offset from reported pseudorange rate for this CorrelationVector */ + @NonNull + public Builder setFrequencyOffsetMetersPerSecond( + @IntRange(from = 0) int frequencyOffsetMetersPerSecond) { + mFrequencyOffsetMetersPerSecond = frequencyOffsetMetersPerSecond; + return this; + } + + /** Sets the data array representing normalized correlation magnitude values. */ + @NonNull + public Builder setMagnitude(@NonNull int[] magnitude) { + mMagnitude = magnitude; + return this; + } + + /** + * Build CorrelationVector object. + * + * @return instance of CorrelationVector + */ + @NonNull + public CorrelationVector build() { + return new CorrelationVector(this); + } + } +} diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java index b650a9fd0416d..a5e28158ab788 100644 --- a/location/java/android/location/GnssCapabilities.java +++ b/location/java/android/location/GnssCapabilities.java @@ -58,6 +58,8 @@ public final class GnssCapabilities implements Parcelable { /** @hide */ public static final int TOP_HAL_CAPABILITY_ANTENNA_INFO = 2048; /** @hide */ + public static final int TOP_HAL_CAPABILITY_CORRELATION_VECTOR = 4096; + /** @hide */ public static final int TOP_HAL_CAPABILITY_SATELLITE_PVT = 8192; /** @hide */ @@ -67,7 +69,8 @@ public final class GnssCapabilities implements Parcelable { TOP_HAL_CAPABILITY_MEASUREMENTS, TOP_HAL_CAPABILITY_NAV_MESSAGES, TOP_HAL_CAPABILITY_LOW_POWER_MODE, TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST, TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS, TOP_HAL_CAPABILITY_ANTENNA_INFO, - TOP_HAL_CAPABILITY_SATELLITE_PVT}) + TOP_HAL_CAPABILITY_CORRELATION_VECTOR, TOP_HAL_CAPABILITY_SATELLITE_PVT}) + @Retention(RetentionPolicy.SOURCE) public @interface TopHalCapabilityFlags {} @@ -336,6 +339,17 @@ public final class GnssCapabilities implements Parcelable { return (mTopFlags & TOP_HAL_CAPABILITY_ANTENNA_INFO) != 0; } + /** + * Returns {@code true} if GNSS chipset supports correlation vectors as part of measurements + * outputs, {@code false} otherwise. + * + * @hide + */ + @SystemApi + public boolean hasMeasurementCorrelationVectors() { + return (mTopFlags & TOP_HAL_CAPABILITY_CORRELATION_VECTOR) != 0; + } + /** * Returns {@code true} if GNSS chipset supports line-of-sight satellite identification * measurement corrections, {@code false} otherwise. @@ -533,6 +547,9 @@ public final class GnssCapabilities implements Parcelable { if (hasAntennaInfo()) { builder.append("ANTENNA_INFO "); } + if (hasMeasurementCorrelationVectors()) { + builder.append("MEASUREMENT_CORRELATION_VECTORS "); + } if (hasMeasurementCorrectionsLosSats()) { builder.append("LOS_SATS "); } @@ -719,6 +736,17 @@ public final class GnssCapabilities implements Parcelable { return this; } + /** + * Sets correlation vector capability. + * + * @hide + */ + @SystemApi + public @NonNull Builder setHasMeasurementCorrelationVectors(boolean capable) { + mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_CORRELATION_VECTOR, capable); + return this; + } + /** * Sets measurement corrections line-of-sight satellites capabilitity. * diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java index 5509a6c656148..c3615fed3a0e7 100644 --- a/location/java/android/location/GnssMeasurement.java +++ b/location/java/android/location/GnssMeasurement.java @@ -38,6 +38,9 @@ import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; /** * A class representing a GNSS satellite measurement, containing raw and computed information. @@ -70,6 +73,7 @@ public final class GnssMeasurement implements Parcelable { private double mSatelliteInterSignalBiasNanos; private double mSatelliteInterSignalBiasUncertaintyNanos; @Nullable private SatellitePvt mSatellitePvt; + @Nullable private Collection mReadOnlyCorrelationVectors; // The following enumerations must be in sync with the values declared in GNSS HAL. @@ -77,6 +81,7 @@ public final class GnssMeasurement implements Parcelable { private static final int HAS_CODE_TYPE = (1 << 14); private static final int HAS_BASEBAND_CN0 = (1 << 15); private static final int HAS_SATELLITE_PVT = (1 << 20); + private static final int HAS_CORRELATION_VECTOR = (1 << 21); /** * The status of the multipath indicator. @@ -279,6 +284,7 @@ public final class GnssMeasurement implements Parcelable { mSatelliteInterSignalBiasUncertaintyNanos = measurement.mSatelliteInterSignalBiasUncertaintyNanos; mSatellitePvt = measurement.mSatellitePvt; + mReadOnlyCorrelationVectors = measurement.mReadOnlyCorrelationVectors; } /** @@ -1712,6 +1718,7 @@ public final class GnssMeasurement implements Parcelable { * *

The value is only available if {@link #hasSatellitePvt()} is * {@code true}. + * * @hide */ @Nullable @@ -1745,6 +1752,58 @@ public final class GnssMeasurement implements Parcelable { resetFlag(HAS_SATELLITE_PVT); } + /** + * Returns {@code true} if {@link #getCorrelationVectors()} is available, + * {@code false} otherwise. + * + * @hide + */ + @SystemApi + public boolean hasCorrelationVectors() { + return isFlagSet(HAS_CORRELATION_VECTOR); + } + + /** + * Gets read-only collection of CorrelationVector with each CorrelationVector corresponding to a + * frequency offset. + * + *

To represent correlation values over a 2D spaces (delay and frequency), a + * CorrelationVector is required per frequency offset, and each CorrelationVector contains + * correlation values at equally spaced spatial offsets. + * + * @hide + */ + @Nullable + @SystemApi + public Collection getCorrelationVectors() { + return mReadOnlyCorrelationVectors; + } + + /** + * Sets the CorrelationVectors. + * + * @hide + */ + @TestApi + public void setCorrelationVectors(@Nullable Collection correlationVectors) { + if (correlationVectors == null || correlationVectors.isEmpty()) { + resetCorrelationVectors(); + } else { + setFlag(HAS_CORRELATION_VECTOR); + mReadOnlyCorrelationVectors = Collections.unmodifiableCollection(correlationVectors); + } + } + + /** + * Resets the CorrelationVectors. + * + * @hide + */ + @TestApi + public void resetCorrelationVectors() { + resetFlag(HAS_CORRELATION_VECTOR); + mReadOnlyCorrelationVectors = null; + } public static final @NonNull Creator CREATOR = new Creator() { @Override @@ -1781,6 +1840,15 @@ public final class GnssMeasurement implements Parcelable { ClassLoader classLoader = getClass().getClassLoader(); gnssMeasurement.mSatellitePvt = parcel.readParcelable(classLoader); } + if (gnssMeasurement.hasCorrelationVectors()) { + CorrelationVector[] correlationVectorsArray = + new CorrelationVector[parcel.readInt()]; + parcel.readTypedArray(correlationVectorsArray, CorrelationVector.CREATOR); + Collection corrVecCollection = + Arrays.asList(correlationVectorsArray); + gnssMeasurement.mReadOnlyCorrelationVectors = + Collections.unmodifiableCollection(corrVecCollection); + } return gnssMeasurement; } @@ -1821,6 +1889,13 @@ public final class GnssMeasurement implements Parcelable { if (hasSatellitePvt()) { parcel.writeParcelable(mSatellitePvt, flags); } + if (hasCorrelationVectors()) { + int correlationVectorCount = mReadOnlyCorrelationVectors.size(); + CorrelationVector[] correlationVectorArray = + mReadOnlyCorrelationVectors.toArray(new CorrelationVector[correlationVectorCount]); + parcel.writeInt(correlationVectorArray.length); + parcel.writeTypedArray(correlationVectorArray, flags); + } } @Override @@ -1928,6 +2003,13 @@ public final class GnssMeasurement implements Parcelable { builder.append(mSatellitePvt.toString()); } + if (hasCorrelationVectors()) { + for (CorrelationVector correlationVector : mReadOnlyCorrelationVectors) { + builder.append(correlationVector.toString()); + builder.append("\n"); + } + } + return builder.toString(); } @@ -1958,6 +2040,7 @@ public final class GnssMeasurement implements Parcelable { resetSatelliteInterSignalBiasNanos(); resetSatelliteInterSignalBiasUncertaintyNanos(); resetSatellitePvt(); + resetCorrelationVectors(); } private void setFlag(int flag) { diff --git a/location/java/android/location/GnssMeasurementRequest.java b/location/java/android/location/GnssMeasurementRequest.java index 613f5918b7085..f509252e7542e 100644 --- a/location/java/android/location/GnssMeasurementRequest.java +++ b/location/java/android/location/GnssMeasurementRequest.java @@ -17,20 +17,38 @@ package android.location; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; + /** * This class contains extra parameters to pass in a GNSS measurement request. */ public final class GnssMeasurementRequest implements Parcelable { + private final boolean mCorrelationVectorOutputsEnabled; private final boolean mFullTracking; /** * Creates a {@link GnssMeasurementRequest} with a full list of parameters. */ - private GnssMeasurementRequest(boolean fullTracking) { + private GnssMeasurementRequest(boolean fullTracking, boolean correlationVectorOutputsEnabled) { mFullTracking = fullTracking; + mCorrelationVectorOutputsEnabled = correlationVectorOutputsEnabled; + } + + /** + * Represents whether to enable correlation vector outputs. + * + *

If true, enable correlation vectors as part of the raw GNSS measurements outputs. + * If false, disable correlation vectors. + * + * @hide + */ + @SystemApi + public boolean isCorrelationVectorOutputsEnabled() { + return mCorrelationVectorOutputsEnabled; } /** @@ -56,7 +74,7 @@ public final class GnssMeasurementRequest implements Parcelable { @Override @NonNull public GnssMeasurementRequest createFromParcel(@NonNull Parcel parcel) { - return new GnssMeasurementRequest(parcel.readBoolean()); + return new GnssMeasurementRequest(parcel.readBoolean(), parcel.readBoolean()); } @Override @@ -68,6 +86,7 @@ public final class GnssMeasurementRequest implements Parcelable { @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { parcel.writeBoolean(mFullTracking); + parcel.writeBoolean(mCorrelationVectorOutputsEnabled); } @NonNull @@ -78,6 +97,9 @@ public final class GnssMeasurementRequest implements Parcelable { if (mFullTracking) { s.append("FullTracking"); } + if (mCorrelationVectorOutputsEnabled) { + s.append(", CorrelationVectorOutPuts"); + } s.append(']'); return s.toString(); } @@ -90,13 +112,15 @@ public final class GnssMeasurementRequest implements Parcelable { GnssMeasurementRequest other = (GnssMeasurementRequest) obj; if (mFullTracking != other.mFullTracking) return false; - + if (mCorrelationVectorOutputsEnabled != other.mCorrelationVectorOutputsEnabled) { + return false; + } return true; } @Override public int hashCode() { - return mFullTracking ? 1 : 0; + return Objects.hash(mFullTracking, mCorrelationVectorOutputsEnabled); } @Override @@ -106,6 +130,7 @@ public final class GnssMeasurementRequest implements Parcelable { /** Builder for {@link GnssMeasurementRequest} */ public static final class Builder { + private boolean mCorrelationVectorOutputsEnabled; private boolean mFullTracking; /** @@ -118,9 +143,24 @@ public final class GnssMeasurementRequest implements Parcelable { * Constructs a {@link Builder} instance by copying a {@link GnssMeasurementRequest}. */ public Builder(@NonNull GnssMeasurementRequest request) { + mCorrelationVectorOutputsEnabled = request.isCorrelationVectorOutputsEnabled(); mFullTracking = request.isFullTracking(); } + /** + * Set the value of whether to enable correlation vector outputs, which is false by default. + * + *

If true, enable correlation vectors as part of the raw GNSS measurements outputs. + * If false, disable correlation vectors. + * + * @hide + */ + @SystemApi + @NonNull public Builder setCorrelationVectorOutputsEnabled(boolean value) { + mCorrelationVectorOutputsEnabled = value; + return this; + } + /** * Set the value of whether to enable full GNSS tracking, which is false by default. * @@ -146,7 +186,7 @@ public final class GnssMeasurementRequest implements Parcelable { /** Builds a {@link GnssMeasurementRequest} instance as specified by this builder. */ @NonNull public GnssMeasurementRequest build() { - return new GnssMeasurementRequest(mFullTracking); + return new GnssMeasurementRequest(mFullTracking, mCorrelationVectorOutputsEnabled); } } } diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 2dc9eb44236f5..0ce1ad0d93807 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -3171,7 +3171,9 @@ public class LocationManager { for (GnssMeasurementRequest request : requests) { if (request.isFullTracking()) { builder.setFullTracking(true); - break; + } + if (request.isCorrelationVectorOutputsEnabled()) { + builder.setCorrelationVectorOutputsEnabled(true); } } diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index 92957aaf29768..b6695c20bd975 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -193,7 +193,9 @@ public class GnssManagerService { IGnssMeasurementsListener listener, String packageName, @Nullable String attributionTag) { mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - + if (request.isCorrelationVectorOutputsEnabled()) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); + } CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag); mGnssMeasurementsProvider.addListener(request, identity, listener); } diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java index b623e279d9ae5..305bc9b69e394 100644 --- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java @@ -118,7 +118,8 @@ public final class GnssMeasurementsProvider extends @Override protected boolean registerWithService(GnssMeasurementRequest request, Collection registrations) { - if (mGnssNative.startMeasurementCollection(request.isFullTracking())) { + if (mGnssNative.startMeasurementCollection(request.isFullTracking(), + request.isCorrelationVectorOutputsEnabled())) { if (D) { Log.d(TAG, "starting gnss measurements (" + request + ")"); } @@ -160,18 +161,26 @@ public final class GnssMeasurementsProvider extends protected GnssMeasurementRequest mergeRegistrations( Collection registrations) { boolean fullTracking = false; + boolean enableCorrVecOutputs = false; + if (mSettingsHelper.isGnssMeasurementsFullTrackingEnabled()) { fullTracking = true; - } else { - for (GnssListenerRegistration registration : registrations) { - if (registration.getRequest().isFullTracking()) { - fullTracking = true; - break; - } + } + + for (GnssListenerRegistration registration : registrations) { + GnssMeasurementRequest request = registration.getRequest(); + if (request.isFullTracking()) { + fullTracking = true; + } + if (request.isCorrelationVectorOutputsEnabled()) { + enableCorrVecOutputs = true; } } - return new GnssMeasurementRequest.Builder().setFullTracking(fullTracking).build(); + return new GnssMeasurementRequest.Builder() + .setFullTracking(fullTracking) + .setCorrelationVectorOutputsEnabled(enableCorrVecOutputs) + .build(); } @Override diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java index 402e84b959c6a..7e2f089d32c90 100644 --- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java +++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java @@ -733,9 +733,10 @@ public class GnssNative { /** * Starts measurement collection. */ - public boolean startMeasurementCollection(boolean enableFullTracking) { + public boolean startMeasurementCollection(boolean enableFullTracking, + boolean enableCorrVecOutputs) { Preconditions.checkState(mRegistered); - return mGnssHal.startMeasurementCollection(enableFullTracking); + return mGnssHal.startMeasurementCollection(enableFullTracking, enableCorrVecOutputs); } /** @@ -1274,8 +1275,9 @@ public class GnssNative { return native_is_measurement_supported(); } - protected boolean startMeasurementCollection(boolean enableFullTracking) { - return native_start_measurement_collection(enableFullTracking); + protected boolean startMeasurementCollection(boolean enableFullTracking, + boolean enableCorrVecOutputs) { + return native_start_measurement_collection(enableFullTracking, enableCorrVecOutputs); } protected boolean stopMeasurementCollection() { @@ -1438,7 +1440,8 @@ public class GnssNative { private static native boolean native_is_measurement_supported(); - private static native boolean native_start_measurement_collection(boolean enableFullTracking); + private static native boolean native_start_measurement_collection(boolean enableFullTracking, + boolean enableCorrVecOutputs); private static native boolean native_stop_measurement_collection(); diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java index 675274bf82c4e..69fe140a7863b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java @@ -233,6 +233,7 @@ public final class FakeGnssHal extends GnssNative.GnssHal { private boolean mAntennaInfoListeningStarted = false; private boolean mMeasurementCollectionStarted = false; private boolean mMeasurementCollectionFullTracking = false; + private boolean mMeasurementCollectionCorrVecOutputsEnabled = false; private GnssHalPositionMode mPositionMode = new GnssHalPositionMode(); private GnssHalBatchingMode mBatchingMode = new GnssHalBatchingMode(); private final ArrayList mBatchedLocations = new ArrayList<>(); @@ -521,9 +522,11 @@ public final class FakeGnssHal extends GnssNative.GnssHal { } @Override - protected boolean startMeasurementCollection(boolean enableFullTracking) { + protected boolean startMeasurementCollection(boolean enableFullTracking, + boolean enableCorrVecOutputs) { mState.mMeasurementCollectionStarted = true; mState.mMeasurementCollectionFullTracking = enableFullTracking; + mState.mMeasurementCollectionCorrVecOutputsEnabled = enableCorrVecOutputs; return true; } @@ -531,6 +534,7 @@ public final class FakeGnssHal extends GnssNative.GnssHal { protected boolean stopMeasurementCollection() { mState.mMeasurementCollectionStarted = false; mState.mMeasurementCollectionFullTracking = false; + mState.mMeasurementCollectionCorrVecOutputsEnabled = false; return true; }