Yu-Han Yang 97f3b91c53 Add GnssExcessPathInfo (frameworks/base)
Also add combinedAttenuationDb in GnssSingleSatCorrection

Bug: 201253590
Test: atest GnssExcessPathInfoTest
      atest GnssSingleSatCorrectionTest
Change-Id: I7f629f2fbca563a36d1b4543f768b8fabd5d91fd
2022-03-16 12:11:22 -07:00

376 lines
14 KiB
Java

/*
* Copyright (C) 2022 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 static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_ATTENUATION;
import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
import java.util.Objects;
/**
* Contains the info of an excess path signal caused by reflection
*
* @hide
*/
@SystemApi
public final class GnssExcessPathInfo implements Parcelable {
private static final int HAS_EXCESS_PATH_LENGTH_MASK = EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
private static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK =
EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
private static final int HAS_REFLECTING_PLANE_MASK = EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
private static final int HAS_ATTENUATION_MASK = EXCESS_PATH_INFO_HAS_ATTENUATION;
/* A bitmask of fields present in this object (see HAS_* constants defined above) */
private final int mFlags;
private final float mExcessPathLengthMeters;
private final float mExcessPathLengthUncertaintyMeters;
@Nullable
private final GnssReflectingPlane mReflectingPlane;
private final float mAttenuationDb;
private GnssExcessPathInfo(
int flags,
float excessPathLengthMeters,
float excessPathLengthUncertaintyMeters,
@Nullable GnssReflectingPlane reflectingPlane,
float attenuationDb) {
mFlags = flags;
mExcessPathLengthMeters = excessPathLengthMeters;
mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
mReflectingPlane = reflectingPlane;
mAttenuationDb = attenuationDb;
}
/**
* Gets a bitmask of fields present in this object.
*
* <p>This API exists for JNI since it is easier for JNI to get one integer flag than looking up
* several has* methods.
* @hide
*/
public int getFlags() {
return mFlags;
}
/** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
public boolean hasExcessPathLength() {
return (mFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
}
/**
* Returns the excess path length to be subtracted from pseudorange before using it in
* calculating location.
*
* <p>{@link #hasExcessPathLength()} must be true when calling this method. Otherwise, an
* {@link UnsupportedOperationException} will be thrown.
*/
@FloatRange(from = 0.0f)
public float getExcessPathLengthMeters() {
if (!hasExcessPathLength()) {
throw new UnsupportedOperationException(
"getExcessPathLengthMeters() is not supported when hasExcessPathLength() is "
+ "false");
}
return mExcessPathLengthMeters;
}
/** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
public boolean hasExcessPathLengthUncertainty() {
return (mFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
}
/**
* Returns the error estimate (1-sigma) for the excess path length estimate.
*
* <p>{@link #hasExcessPathLengthUncertainty()} must be true when calling this method.
* Otherwise, an {@link UnsupportedOperationException} will be thrown.
*/
@FloatRange(from = 0.0f)
public float getExcessPathLengthUncertaintyMeters() {
if (!hasExcessPathLengthUncertainty()) {
throw new UnsupportedOperationException(
"getExcessPathLengthUncertaintyMeters() is not supported when "
+ "hasExcessPathLengthUncertainty() is false");
}
return mExcessPathLengthUncertaintyMeters;
}
/**
* Returns {@code true} if {@link #getReflectingPlane()} is valid.
*
* <p>Returns false if the satellite signal goes through multiple reflections or if reflection
* plane serving is not supported.
*/
public boolean hasReflectingPlane() {
return (mFlags & HAS_REFLECTING_PLANE_MASK) != 0;
}
/**
* Returns the reflecting plane characteristics at which the signal has bounced.
*
* <p>{@link #hasReflectingPlane()} must be true when calling this method. Otherwise, an
* {@link UnsupportedOperationException} will be thrown.
*/
@NonNull
public GnssReflectingPlane getReflectingPlane() {
if (!hasReflectingPlane()) {
throw new UnsupportedOperationException(
"getReflectingPlane() is not supported when hasReflectingPlane() is false");
}
return mReflectingPlane;
}
/** Returns {@code true} if {@link #getAttenuationDb()} is valid. */
public boolean hasAttenuation() {
return (mFlags & HAS_ATTENUATION_MASK) != 0;
}
/**
* Returns the expected reduction of signal strength of this path in non-negative dB.
*
* <p>{@link #hasAttenuation()} must be true when calling this method. Otherwise, an
* {@link UnsupportedOperationException} will be thrown.
*/
@FloatRange(from = 0.0f)
public float getAttenuationDb() {
if (!hasAttenuation()) {
throw new UnsupportedOperationException(
"getAttenuationDb() is not supported when hasAttenuation() is false");
}
return mAttenuationDb;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int parcelFlags) {
parcel.writeInt(mFlags);
if (hasExcessPathLength()) {
parcel.writeFloat(mExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
}
if (hasReflectingPlane()) {
mReflectingPlane.writeToParcel(parcel, parcelFlags);
}
if (hasAttenuation()) {
parcel.writeFloat(mAttenuationDb);
}
}
public static final @NonNull Creator<GnssExcessPathInfo> CREATOR =
new Creator<GnssExcessPathInfo>() {
@Override
@NonNull
public GnssExcessPathInfo createFromParcel(@NonNull Parcel parcel) {
int flags = parcel.readInt();
float excessPathLengthMeters =
(flags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
? parcel.readFloat() : 0;
float excessPathLengthUncertaintyMeters =
(flags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
? parcel.readFloat() : 0;
GnssReflectingPlane reflectingPlane =
(flags & HAS_REFLECTING_PLANE_MASK) != 0
? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
float attenuationDb =
(flags & HAS_ATTENUATION_MASK) != 0
? parcel.readFloat() : 0;
return new GnssExcessPathInfo(flags, excessPathLengthMeters,
excessPathLengthUncertaintyMeters, reflectingPlane, attenuationDb);
}
@Override
public GnssExcessPathInfo[] newArray(int i) {
return new GnssExcessPathInfo[i];
}
};
@Override
public boolean equals(Object obj) {
if (obj instanceof GnssExcessPathInfo) {
GnssExcessPathInfo that = (GnssExcessPathInfo) obj;
return this.mFlags == that.mFlags
&& (!hasExcessPathLength() || Float.compare(this.mExcessPathLengthMeters,
that.mExcessPathLengthMeters) == 0)
&& (!hasExcessPathLengthUncertainty() || Float.compare(
this.mExcessPathLengthUncertaintyMeters,
that.mExcessPathLengthUncertaintyMeters) == 0)
&& (!hasReflectingPlane() || Objects.equals(this.mReflectingPlane,
that.mReflectingPlane))
&& (!hasAttenuation() || Float.compare(this.mAttenuationDb,
that.mAttenuationDb) == 0);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(mFlags,
mExcessPathLengthMeters,
mExcessPathLengthUncertaintyMeters,
mReflectingPlane,
mAttenuationDb);
}
@NonNull
@Override
public String toString() {
StringBuilder builder = new StringBuilder("GnssExcessPathInfo[");
if (hasExcessPathLength()) {
builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
builder.append(" ExcessPathLengthUncertaintyMeters=").append(
mExcessPathLengthUncertaintyMeters);
}
if (hasReflectingPlane()) {
builder.append(" ReflectingPlane=").append(mReflectingPlane);
}
if (hasAttenuation()) {
builder.append(" AttenuationDb=").append(mAttenuationDb);
}
builder.append(']');
return builder.toString();
}
/** Builder for {@link GnssExcessPathInfo}. */
public static final class Builder {
private int mFlags;
private float mExcessPathLengthMeters;
private float mExcessPathLengthUncertaintyMeters;
@Nullable
private GnssReflectingPlane mReflectingPlane;
private float mAttenuationDb;
/** Constructor for {@link Builder}. */
public Builder() {}
/**
* Sets the excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
@NonNull
public Builder setExcessPathLengthMeters(
@FloatRange(from = 0.0f) float excessPathLengthMeters) {
Preconditions.checkArgumentInRange(excessPathLengthMeters, 0, Float.MAX_VALUE,
"excessPathLengthMeters");
mExcessPathLengthMeters = excessPathLengthMeters;
mFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
return this;
}
/**
* Clears the excess path length.
*
* <p>This is to negate {@link #setExcessPathLengthMeters} call.
*/
@NonNull
public Builder clearExcessPathLengthMeters() {
mExcessPathLengthMeters = 0;
mFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
return this;
}
/** Sets the error estimate (1-sigma) for the excess path length estimate */
@NonNull
public Builder setExcessPathLengthUncertaintyMeters(
@FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
Preconditions.checkArgumentInRange(excessPathLengthUncertaintyMeters, 0,
Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
mFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
/**
* Clears the error estimate (1-sigma) for the excess path length estimate
*
* <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
*/
@NonNull
public Builder clearExcessPathLengthUncertaintyMeters() {
mExcessPathLengthUncertaintyMeters = 0;
mFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
/** Sets the reflecting plane information */
@NonNull
public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
mReflectingPlane = reflectingPlane;
if (reflectingPlane != null) {
mFlags |= HAS_REFLECTING_PLANE_MASK;
} else {
mFlags &= ~HAS_REFLECTING_PLANE_MASK;
}
return this;
}
/**
* Sets the attenuation value in dB.
*/
@NonNull
public Builder setAttenuationDb(@FloatRange(from = 0.0f) float attenuationDb) {
Preconditions.checkArgumentInRange(attenuationDb, 0, Float.MAX_VALUE,
"attenuationDb");
mAttenuationDb = attenuationDb;
mFlags |= HAS_ATTENUATION_MASK;
return this;
}
/**
* Clears the attenuation value in dB.
*
* <p>This is to negate {@link #setAttenuationDb(float)} call.
*/
@NonNull
public Builder clearAttenuationDb() {
mAttenuationDb = 0;
mFlags &= ~HAS_ATTENUATION_MASK;
return this;
}
/** Builds a {@link GnssExcessPathInfo} instance as specified by this builder. */
@NonNull
public GnssExcessPathInfo build() {
return new GnssExcessPathInfo(
mFlags,
mExcessPathLengthMeters,
mExcessPathLengthUncertaintyMeters,
mReflectingPlane,
mAttenuationDb);
}
}
}