• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SuppressLint;
23 import android.annotation.SystemApi;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.os.SystemClock;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.util.Objects;
31 
32 /**
33  * Representation of a ranging measurement between the local device and a remote device
34  *
35  * @hide
36  */
37 @SystemApi
38 public final class RangingMeasurement implements Parcelable {
39     private final UwbAddress mRemoteDeviceAddress;
40     private final @Status int mStatus;
41     private final long mElapsedRealtimeNanos;
42     private final DistanceMeasurement mDistanceMeasurement;
43     private final AngleOfArrivalMeasurement mAngleOfArrivalMeasurement;
44 
RangingMeasurement(@onNull UwbAddress remoteDeviceAddress, @Status int status, long elapsedRealtimeNanos, @Nullable DistanceMeasurement distanceMeasurement, @Nullable AngleOfArrivalMeasurement angleOfArrivalMeasurement)45     private RangingMeasurement(@NonNull UwbAddress remoteDeviceAddress, @Status int status,
46             long elapsedRealtimeNanos, @Nullable DistanceMeasurement distanceMeasurement,
47             @Nullable AngleOfArrivalMeasurement angleOfArrivalMeasurement) {
48         mRemoteDeviceAddress = remoteDeviceAddress;
49         mStatus = status;
50         mElapsedRealtimeNanos = elapsedRealtimeNanos;
51         mDistanceMeasurement = distanceMeasurement;
52         mAngleOfArrivalMeasurement = angleOfArrivalMeasurement;
53     }
54 
55     /**
56      * Get the remote device's {@link UwbAddress}
57      *
58      * @return the remote device's {@link UwbAddress}
59      */
60     @NonNull
getRemoteDeviceAddress()61     public UwbAddress getRemoteDeviceAddress() {
62         return mRemoteDeviceAddress;
63     }
64 
65     /**
66      * @hide
67      */
68     @Retention(RetentionPolicy.SOURCE)
69     @IntDef(value = {
70             RANGING_STATUS_SUCCESS,
71             RANGING_STATUS_FAILURE_OUT_OF_RANGE,
72             RANGING_STATUS_FAILURE_UNKNOWN_ERROR})
73     public @interface Status {}
74 
75     /**
76      * Ranging attempt was successful for this device
77      */
78     public static final int RANGING_STATUS_SUCCESS = 0;
79 
80     /**
81      * Ranging failed for this device because it is out of range
82      */
83     public static final int RANGING_STATUS_FAILURE_OUT_OF_RANGE = 1;
84 
85     /**
86      * Ranging failed for this device because of unknown error
87      */
88     public static final int RANGING_STATUS_FAILURE_UNKNOWN_ERROR = -1;
89 
90     /**
91      * Get the status of this ranging measurement
92      *
93      * <p>Possible values are
94      * {@link #RANGING_STATUS_SUCCESS},
95      * {@link #RANGING_STATUS_FAILURE_OUT_OF_RANGE},
96      * {@link #RANGING_STATUS_FAILURE_UNKNOWN_ERROR}.
97      *
98      * @return the status of the ranging measurement
99      */
100     @Status
getStatus()101     public int getStatus() {
102         return mStatus;
103     }
104 
105     /**
106      * Timestamp of this ranging measurement in time since boot nanos in the same namespace as
107      * {@link SystemClock#elapsedRealtimeNanos()}
108      *
109      * @return timestamp of ranging measurement in nanoseconds
110      */
111     @SuppressLint("MethodNameUnits")
getElapsedRealtimeNanos()112     public long getElapsedRealtimeNanos() {
113         return mElapsedRealtimeNanos;
114     }
115 
116     /**
117      * Get the distance measurement
118      *
119      * @return a {@link DistanceMeasurement} or null if {@link #getStatus()} !=
120      *         {@link #RANGING_STATUS_SUCCESS}
121      */
122     @Nullable
getDistanceMeasurement()123     public DistanceMeasurement getDistanceMeasurement() {
124         return mDistanceMeasurement;
125     }
126 
127     /**
128      * Get the angle of arrival measurement
129      *
130      * @return an {@link AngleOfArrivalMeasurement} or null if {@link #getStatus()} !=
131      *         {@link #RANGING_STATUS_SUCCESS}
132      */
133     @Nullable
getAngleOfArrivalMeasurement()134     public AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
135         return mAngleOfArrivalMeasurement;
136     }
137 
138     /**
139      * @hide
140      */
141     @Override
equals(@ullable Object obj)142     public boolean equals(@Nullable Object obj) {
143         if (this == obj) {
144             return true;
145         }
146 
147         if (obj instanceof RangingMeasurement) {
148             RangingMeasurement other = (RangingMeasurement) obj;
149             return mRemoteDeviceAddress.equals(other.getRemoteDeviceAddress())
150                     && mStatus == other.getStatus()
151                     && mElapsedRealtimeNanos == other.getElapsedRealtimeNanos()
152                     && mDistanceMeasurement.equals(other.getDistanceMeasurement())
153                     && mAngleOfArrivalMeasurement.equals(other.getAngleOfArrivalMeasurement());
154         }
155         return false;
156     }
157 
158     /**
159      * @hide
160      */
161     @Override
hashCode()162     public int hashCode() {
163         return Objects.hash(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
164                 mDistanceMeasurement, mAngleOfArrivalMeasurement);
165     }
166 
167     @Override
describeContents()168     public int describeContents() {
169         return 0;
170     }
171 
172     @Override
writeToParcel(@onNull Parcel dest, int flags)173     public void writeToParcel(@NonNull Parcel dest, int flags) {
174         dest.writeParcelable(mRemoteDeviceAddress, flags);
175         dest.writeInt(mStatus);
176         dest.writeLong(mElapsedRealtimeNanos);
177         dest.writeParcelable(mDistanceMeasurement, flags);
178         dest.writeParcelable(mAngleOfArrivalMeasurement, flags);
179     }
180 
181     public static final @android.annotation.NonNull Creator<RangingMeasurement> CREATOR =
182             new Creator<RangingMeasurement>() {
183                 @Override
184                 public RangingMeasurement createFromParcel(Parcel in) {
185                     Builder builder = new Builder();
186                     builder.setRemoteDeviceAddress(
187                             in.readParcelable(UwbAddress.class.getClassLoader()));
188                     builder.setStatus(in.readInt());
189                     builder.setElapsedRealtimeNanos(in.readLong());
190                     builder.setDistanceMeasurement(
191                             in.readParcelable(DistanceMeasurement.class.getClassLoader()));
192                     builder.setAngleOfArrivalMeasurement(
193                             in.readParcelable(AngleOfArrivalMeasurement.class.getClassLoader()));
194                     return builder.build();
195                 }
196 
197                 @Override
198                 public RangingMeasurement[] newArray(int size) {
199                     return new RangingMeasurement[size];
200                 }
201     };
202 
203     /**
204      * Builder for a {@link RangingMeasurement} object.
205      */
206     public static final class Builder {
207         private UwbAddress mRemoteDeviceAddress = null;
208         private @Status int mStatus = RANGING_STATUS_FAILURE_UNKNOWN_ERROR;
209         private long mElapsedRealtimeNanos = -1L;
210         private DistanceMeasurement mDistanceMeasurement = null;
211         private AngleOfArrivalMeasurement mAngleOfArrivalMeasurement = null;
212 
213         /**
214          * Set the remote device address that this measurement is for
215          *
216          * @param remoteDeviceAddress remote device's address
217          */
218         @NonNull
setRemoteDeviceAddress(@onNull UwbAddress remoteDeviceAddress)219         public Builder setRemoteDeviceAddress(@NonNull UwbAddress remoteDeviceAddress) {
220             mRemoteDeviceAddress = remoteDeviceAddress;
221             return this;
222         }
223 
224         /**
225          * Set the status of ranging measurement
226          *
227          * @param status the status of the ranging measurement
228          */
229         @NonNull
setStatus(@tatus int status)230         public Builder setStatus(@Status int status) {
231             mStatus = status;
232             return this;
233         }
234 
235         /**
236          * Set the elapsed realtime in nanoseconds when the ranging measurement occurred
237          *
238          * @param elapsedRealtimeNanos time the ranging measurement occurred
239          */
240         @NonNull
setElapsedRealtimeNanos(long elapsedRealtimeNanos)241         public Builder setElapsedRealtimeNanos(long elapsedRealtimeNanos) {
242             if (elapsedRealtimeNanos < 0) {
243                 throw new IllegalArgumentException("elapsedRealtimeNanos must be >= 0");
244             }
245             mElapsedRealtimeNanos = elapsedRealtimeNanos;
246             return this;
247         }
248 
249         /**
250          * Set the {@link DistanceMeasurement}
251          *
252          * @param distanceMeasurement the distance measurement for this ranging measurement
253          */
254         @NonNull
setDistanceMeasurement(@onNull DistanceMeasurement distanceMeasurement)255         public Builder setDistanceMeasurement(@NonNull DistanceMeasurement distanceMeasurement) {
256             mDistanceMeasurement = distanceMeasurement;
257             return this;
258         }
259 
260         /**
261          * Set the {@link AngleOfArrivalMeasurement}
262          *
263          * @param angleOfArrivalMeasurement the angle of arrival measurement for this ranging
264          *                                  measurement
265          */
266         @NonNull
setAngleOfArrivalMeasurement( @onNull AngleOfArrivalMeasurement angleOfArrivalMeasurement)267         public Builder setAngleOfArrivalMeasurement(
268                 @NonNull AngleOfArrivalMeasurement angleOfArrivalMeasurement) {
269             mAngleOfArrivalMeasurement = angleOfArrivalMeasurement;
270             return this;
271         }
272 
273         /**
274          * Build the {@link RangingMeasurement} object
275          *
276          * @throws IllegalStateException if a distance or angle of arrival measurement is provided
277          *                               but the measurement was not successful, if the
278          *                               elapsedRealtimeNanos of the measurement is invalid, or
279          *                               if no remote device address is set
280          */
281         @NonNull
build()282         public RangingMeasurement build() {
283             if (mStatus != RANGING_STATUS_SUCCESS) {
284                 if (mDistanceMeasurement != null) {
285                     throw new IllegalStateException(
286                             "Distance Measurement must be null if ranging is not successful");
287                 }
288 
289                 if (mAngleOfArrivalMeasurement != null) {
290                     throw new IllegalStateException(
291                             "Angle of Arrival must be null if ranging is not successful");
292                 }
293             }
294 
295             if (mRemoteDeviceAddress == null) {
296                 throw new IllegalStateException("No remote device address was set");
297             }
298 
299             if (mElapsedRealtimeNanos < 0) {
300                 throw new IllegalStateException(
301                         "elapsedRealtimeNanos must be >=0: " + mElapsedRealtimeNanos);
302             }
303 
304             return new RangingMeasurement(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
305                     mDistanceMeasurement, mAngleOfArrivalMeasurement);
306         }
307     }
308 }
309