1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.uwb;
18 
19 import android.annotation.FloatRange;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.util.Objects;
27 
28 /**
29  * A data point for the distance measurement
30  *
31  * <p>The actual distance is interpreted as:
32  *   {@link #getMeters()} +/- {@link #getErrorMeters()} at {@link #getConfidenceLevel()}
33  *
34  * @hide
35  */
36 @SystemApi
37 public final class DistanceMeasurement implements Parcelable {
38     private final double mMeters;
39     private final double mErrorMeters;
40     private final double mConfidenceLevel;
41 
DistanceMeasurement(double meters, double errorMeters, double confidenceLevel)42     private DistanceMeasurement(double meters, double errorMeters, double confidenceLevel) {
43         mMeters = meters;
44         mErrorMeters = errorMeters;
45         mConfidenceLevel = confidenceLevel;
46     }
47 
48     /**
49      * Distance measurement in meters
50      *
51      * @return distance in meters
52      */
getMeters()53     public double getMeters() {
54         return mMeters;
55     }
56 
57     /**
58      * Error of distance measurement in meters
59      * <p>Must be positive
60      *
61      * @return error of distance measurement in meters
62      */
63     @FloatRange(from = 0.0)
getErrorMeters()64     public double getErrorMeters() {
65         return mErrorMeters;
66     }
67 
68     /**
69      * Distance measurement confidence level expressed as a value between 0.0 to 1.0.
70      *
71      * <p>A value of 0.0 indicates no confidence in the measurement. A value of 1.0 represents
72      * maximum confidence in the measurement
73      *
74      * @return confidence level
75      */
76     @FloatRange(from = 0.0, to = 1.0)
getConfidenceLevel()77     public double getConfidenceLevel() {
78         return mConfidenceLevel;
79     }
80 
81     /**
82      * @hide
83      */
84     @Override
equals(@ullable Object obj)85     public boolean equals(@Nullable Object obj) {
86         if (this == obj) {
87             return true;
88         }
89 
90         if (obj instanceof DistanceMeasurement) {
91             DistanceMeasurement other = (DistanceMeasurement) obj;
92             return mMeters == other.getMeters()
93                     && mErrorMeters == other.getErrorMeters()
94                     && mConfidenceLevel == other.getConfidenceLevel();
95         }
96         return false;
97     }
98 
99     /**
100      * @hide
101      */
102     @Override
hashCode()103     public int hashCode() {
104         return Objects.hash(mMeters, mErrorMeters, mConfidenceLevel);
105     }
106 
107     @Override
describeContents()108     public int describeContents() {
109         return 0;
110     }
111 
112     @Override
writeToParcel(@onNull Parcel dest, int flags)113     public void writeToParcel(@NonNull Parcel dest, int flags) {
114         dest.writeDouble(mMeters);
115         dest.writeDouble(mErrorMeters);
116         dest.writeDouble(mConfidenceLevel);
117     }
118 
119     public static final @android.annotation.NonNull Creator<DistanceMeasurement> CREATOR =
120             new Creator<DistanceMeasurement>() {
121                 @Override
122                 public DistanceMeasurement createFromParcel(Parcel in) {
123                     Builder builder = new Builder();
124                     builder.setMeters(in.readDouble());
125                     builder.setErrorMeters(in.readDouble());
126                     builder.setConfidenceLevel(in.readDouble());
127                     return builder.build();
128                 }
129 
130                 @Override
131                 public DistanceMeasurement[] newArray(int size) {
132                     return new DistanceMeasurement[size];
133                 }
134     };
135 
136     /** @hide **/
137     @Override
toString()138     public String toString() {
139         return "DistanceMeasurement["
140                 + "meters: " + mMeters
141                 + ", errorMeters: " + mErrorMeters
142                 + ", confidenceLevel: " + mConfidenceLevel
143                 + "]";
144     }
145 
146     /**
147      * Builder to get a {@link DistanceMeasurement} object.
148      */
149     public static final class Builder {
150         private double mMeters = Double.NaN;
151         private double mErrorMeters = Double.NaN;
152         private double mConfidenceLevel = Double.NaN;
153 
154         /**
155          * Set the distance measurement in meters
156          *
157          * @param meters distance in meters
158          * @throws IllegalArgumentException if meters is NaN
159          */
160         @NonNull
setMeters(double meters)161         public Builder setMeters(double meters) {
162             if (Double.isNaN(meters)) {
163                 throw new IllegalArgumentException("meters cannot be NaN");
164             }
165             mMeters = meters;
166             return this;
167         }
168 
169         /**
170          * Set the distance error in meters
171          *
172          * @param errorMeters distance error in meters
173          * @throws IllegalArgumentException if error is negative or NaN
174          */
175         @NonNull
setErrorMeters(@loatRangefrom = 0.0) double errorMeters)176         public Builder setErrorMeters(@FloatRange(from = 0.0) double errorMeters) {
177             if (Double.isNaN(errorMeters) || errorMeters < 0.0) {
178                 throw new IllegalArgumentException(
179                         "errorMeters must be >= 0.0 and not NaN: " + errorMeters);
180             }
181             mErrorMeters = errorMeters;
182             return this;
183         }
184 
185         /**
186          * Set the confidence level
187          *
188          * @param confidenceLevel the confidence level in the distance measurement
189          * @throws IllegalArgumentException if confidence level is not in the range of [0.0, 1.0]
190          */
191         @NonNull
setConfidenceLevel( @loatRangefrom = 0.0, to = 1.0) double confidenceLevel)192         public Builder setConfidenceLevel(
193                 @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
194             if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
195                 throw new IllegalArgumentException(
196                         "confidenceLevel must be in the range [0.0, 1.0]: " + confidenceLevel);
197             }
198             mConfidenceLevel = confidenceLevel;
199             return this;
200         }
201 
202         /**
203          * Builds the {@link DistanceMeasurement} object
204          *
205          * @throws IllegalStateException if meters, error, or confidence are not set
206          */
207         @NonNull
build()208         public DistanceMeasurement build() {
209             if (Double.isNaN(mMeters)) {
210                 throw new IllegalStateException("Meters cannot be NaN");
211             }
212 
213             if (Double.isNaN(mErrorMeters)) {
214                 throw new IllegalStateException("Error meters cannot be NaN");
215             }
216 
217             if (Double.isNaN(mConfidenceLevel)) {
218                 throw new IllegalStateException("Confidence level cannot be NaN");
219             }
220 
221             return new DistanceMeasurement(mMeters, mErrorMeters, mConfidenceLevel);
222         }
223     }
224 }
225