| /* |
| * 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); |
| } |
| } |
| } |