• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.bluetooth.le;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.FloatRange;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.SystemApi;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 
27 import com.android.bluetooth.flags.Flags;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 
32 /**
33  * Result of distance measurement.
34  *
35  * @hide
36  */
37 @SystemApi
38 public final class DistanceMeasurementResult implements Parcelable {
39 
40     /**
41      * Normalized Attack Detector Metric. See Channel Sounding CR_PR, 3.13.24 for details.
42      *
43      * <p>Specification: https://www.bluetooth.com/specifications/specs/channel-sounding-cr-pr/
44      *
45      * @hide
46      */
47     @Retention(RetentionPolicy.SOURCE)
48     @IntDef(
49             value = {
50                 NADM_ATTACK_IS_EXTREMELY_UNLIKELY,
51                 NADM_ATTACK_IS_VERY_UNLIKELY,
52                 NADM_ATTACK_IS_UNLIKELY,
53                 NADM_ATTACK_IS_POSSIBLE,
54                 NADM_ATTACK_IS_LIKELY,
55                 NADM_ATTACK_IS_VERY_LIKELY,
56                 NADM_ATTACK_IS_EXTREMELY_LIKELY,
57                 NADM_UNKNOWN
58             })
59     @interface Nadm {}
60 
61     /**
62      * Attack is extremely unlikely.
63      *
64      * @hide
65      */
66     @SystemApi
67     public static final int NADM_ATTACK_IS_EXTREMELY_UNLIKELY = 0;
68 
69     /**
70      * Attack is very unlikely.
71      *
72      * @hide
73      */
74     @SystemApi
75     public static final int NADM_ATTACK_IS_VERY_UNLIKELY = 1;
76 
77     /**
78      * Attack is unlikely.
79      *
80      * @hide
81      */
82     @SystemApi
83     public static final int NADM_ATTACK_IS_UNLIKELY = 2;
84 
85     /**
86      * Attack is possible.
87      *
88      * @hide
89      */
90     @SystemApi
91     public static final int NADM_ATTACK_IS_POSSIBLE = 3;
92 
93     /**
94      * Attack is likely.
95      *
96      * @hide
97      */
98     @SystemApi
99     public static final int NADM_ATTACK_IS_LIKELY = 4;
100 
101     /**
102      * Attack is very likely.
103      *
104      * @hide
105      */
106     @SystemApi
107     public static final int NADM_ATTACK_IS_VERY_LIKELY = 5;
108 
109     /**
110      * Attack is extremely likely.
111      *
112      * @hide
113      */
114     @SystemApi
115     public static final int NADM_ATTACK_IS_EXTREMELY_LIKELY = 6;
116 
117     /**
118      * Unknown NADM, if a device is unable to determine a NADM value, then it shall report this.
119      *
120      * @hide
121      */
122     @SystemApi
123     public static final int NADM_UNKNOWN = 0xFF;
124 
125     private final double mMeters;
126     private final double mErrorMeters;
127     private final double mAzimuthAngle;
128     private final double mErrorAzimuthAngle;
129     private final double mAltitudeAngle;
130     private final double mErrorAltitudeAngle;
131     private final double mDelaySpreadMeters;
132     private final double mConfidenceLevel;
133     private final int mDetectedAttackLevel;
134     private final double mVelocityMetersPerSecond;
135     private final long mMeasurementTimestampNanos;
136 
DistanceMeasurementResult( double meters, double errorMeters, double azimuthAngle, double errorAzimuthAngle, double altitudeAngle, double errorAltitudeAngle, double delaySpreadMeters, double confidenceLevel, @Nadm int detectedAttackLevel, double velocityMetersPerSecond, long measurementTimestampNanos)137     private DistanceMeasurementResult(
138             double meters,
139             double errorMeters,
140             double azimuthAngle,
141             double errorAzimuthAngle,
142             double altitudeAngle,
143             double errorAltitudeAngle,
144             double delaySpreadMeters,
145             double confidenceLevel,
146             @Nadm int detectedAttackLevel,
147             double velocityMetersPerSecond,
148             long measurementTimestampNanos) {
149         mMeters = meters;
150         mErrorMeters = errorMeters;
151         mAzimuthAngle = azimuthAngle;
152         mErrorAzimuthAngle = errorAzimuthAngle;
153         mAltitudeAngle = altitudeAngle;
154         mErrorAltitudeAngle = errorAltitudeAngle;
155         mDelaySpreadMeters = delaySpreadMeters;
156         mConfidenceLevel = confidenceLevel;
157         mDetectedAttackLevel = detectedAttackLevel;
158         mVelocityMetersPerSecond = velocityMetersPerSecond;
159         mMeasurementTimestampNanos = measurementTimestampNanos;
160     }
161 
162     /**
163      * Distance measurement in meters.
164      *
165      * @return distance in meters
166      * @hide
167      */
168     @SystemApi
getResultMeters()169     public double getResultMeters() {
170         return mMeters;
171     }
172 
173     /**
174      * Error of distance measurement in meters.
175      *
176      * <p>Must be positive.
177      *
178      * @return error of distance measurement in meters
179      * @hide
180      */
181     @SystemApi
182     @FloatRange(from = 0.0)
getErrorMeters()183     public double getErrorMeters() {
184         return mErrorMeters;
185     }
186 
187     /**
188      * Azimuth Angle measurement in degrees.
189      *
190      * <p>Azimuth of remote device in horizontal coordinate system, this measured from azimuth north
191      * and increasing eastward. When the remote device in azimuth north, this angle is 0, whe the
192      * remote device in azimuth south, this angle is 180.
193      *
194      * <p>See: <a href="https://en.wikipedia.org/wiki/Horizontal_coordinate_system">Horizontal
195      * coordinate system</a>for the details
196      *
197      * <p>On an Android device, azimuth north is defined as the angle perpendicular away from the
198      * back of the device when holding it in portrait mode upright.
199      *
200      * <p>The Azimuth north is defined as the direction in which the top edge of the device is
201      * facing when it is placed flat.
202      *
203      * @return azimuth angle in degrees or Double.NaN if not available
204      * @hide
205      */
206     @SystemApi
207     @FloatRange(from = 0.0, to = 360.0)
getAzimuthAngle()208     public double getAzimuthAngle() {
209         return mAzimuthAngle;
210     }
211 
212     /**
213      * Error of azimuth angle measurement in degrees.
214      *
215      * <p>Must be a positive value.
216      *
217      * @return azimuth angle measurement error in degrees or Double.NaN if not available
218      * @hide
219      */
220     @SystemApi
getErrorAzimuthAngle()221     public double getErrorAzimuthAngle() {
222         return mErrorAzimuthAngle;
223     }
224 
225     /**
226      * Altitude Angle measurement in degrees.
227      *
228      * <p>Altitude of remote device in horizontal coordinate system, this is the angle between the
229      * remote device and the top edge of local device. When local device is placed flat, the angle
230      * of the zenith is 90, the angle of the nadir is -90.
231      *
232      * <p>See: https://en.wikipedia.org/wiki/Horizontal_coordinate_system
233      *
234      * @return altitude angle in degrees or Double.NaN if not available
235      * @hide
236      */
237     @SystemApi
238     @FloatRange(from = -90.0, to = 90.0)
getAltitudeAngle()239     public double getAltitudeAngle() {
240         return mAltitudeAngle;
241     }
242 
243     /**
244      * Error of altitude angle measurement in degrees.
245      *
246      * <p>Must be a positive value.
247      *
248      * @return altitude angle measurement error in degrees or Double.NaN if not available
249      * @hide
250      */
251     @SystemApi
getErrorAltitudeAngle()252     public double getErrorAltitudeAngle() {
253         return mErrorAltitudeAngle;
254     }
255 
256     /**
257      * Get estimated delay spread in meters of the measured channel. This is a measure of multipath
258      * richness of the channel.
259      *
260      * @return delay spread in meters in degrees or Double.NaN if not available
261      * @hide
262      */
263     @SystemApi
getDelaySpreadMeters()264     public double getDelaySpreadMeters() {
265         return mDelaySpreadMeters;
266     }
267 
268     /**
269      * Get a normalized value from 0.0 (low confidence) to 1.0 (high confidence) representing the
270      * confidence of estimated distance.
271      *
272      * @return confidence of estimated distance or Double.NaN if not available
273      * @hide
274      */
275     @SystemApi
276     @FloatRange(from = 0.0, to = 1.0)
getConfidenceLevel()277     public double getConfidenceLevel() {
278         return mConfidenceLevel;
279     }
280 
281     /**
282      * Get a value that represents the chance of being attacked for the measurement.
283      *
284      * @return Nadm that represents the chance of being attacked for the measurement.
285      * @hide
286      */
287     @SystemApi
288     @Nadm
getDetectedAttackLevel()289     public int getDetectedAttackLevel() {
290         return mDetectedAttackLevel;
291     }
292 
293     /**
294      * Get estimated velocity, in the direction of line between two devices, of the moving object in
295      * meters/sec.
296      *
297      * @return Estimated velocity, in the direction of line between two devices, of the moving
298      *     object in meters/sec.
299      * @hide
300      */
301     @SystemApi
getVelocityMetersPerSecond()302     public double getVelocityMetersPerSecond() {
303         return mVelocityMetersPerSecond;
304     }
305 
306     /**
307      * Timestamp of this distance measurement in time since boot nanos in the same namespace as
308      * {@link SystemClock#elapsedRealtimeNanos()}
309      *
310      * @return timestamp of ranging measurement in nanoseconds
311      * @hide
312      */
313     @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING_25Q2_APIS)
314     @SystemApi
getMeasurementTimestampNanos()315     public long getMeasurementTimestampNanos() {
316         return mMeasurementTimestampNanos;
317     }
318 
319     /**
320      * {@inheritDoc}
321      *
322      * @hide
323      */
324     @Override
describeContents()325     public int describeContents() {
326         return 0;
327     }
328 
329     /**
330      * {@inheritDoc}
331      *
332      * @hide
333      */
334     @Override
writeToParcel(Parcel out, int flags)335     public void writeToParcel(Parcel out, int flags) {
336         out.writeDouble(mMeters);
337         out.writeDouble(mErrorMeters);
338         out.writeDouble(mAzimuthAngle);
339         out.writeDouble(mErrorAzimuthAngle);
340         out.writeDouble(mAltitudeAngle);
341         out.writeDouble(mErrorAltitudeAngle);
342         out.writeDouble(mDelaySpreadMeters);
343         out.writeDouble(mConfidenceLevel);
344         out.writeInt(mDetectedAttackLevel);
345         out.writeDouble(mVelocityMetersPerSecond);
346         out.writeLong(mMeasurementTimestampNanos);
347     }
348 
349     /**
350      * @hide *
351      */
352     @Override
toString()353     public String toString() {
354         return "DistanceMeasurement["
355                 + "meters: "
356                 + mMeters
357                 + ", errorMeters: "
358                 + mErrorMeters
359                 + ", azimuthAngle: "
360                 + mAzimuthAngle
361                 + ", errorAzimuthAngle: "
362                 + mErrorAzimuthAngle
363                 + ", altitudeAngle: "
364                 + mAltitudeAngle
365                 + ", errorAltitudeAngle: "
366                 + mErrorAltitudeAngle
367                 + ", delaySpreadMeters: "
368                 + mDelaySpreadMeters
369                 + ", confidenceLevel: "
370                 + mConfidenceLevel
371                 + ", detectedAttackLevel: "
372                 + mDetectedAttackLevel
373                 + ", velocityMetersPerSecond: "
374                 + mVelocityMetersPerSecond
375                 + ", elapsedRealtimeNanos"
376                 + mMeasurementTimestampNanos
377                 + "]";
378     }
379 
380     /** A {@link Parcelable.Creator} to create {@link DistanceMeasurementResult} from parcel. */
381     public static final @NonNull Parcelable.Creator<DistanceMeasurementResult> CREATOR =
382             new Parcelable.Creator<DistanceMeasurementResult>() {
383                 @Override
384                 public @NonNull DistanceMeasurementResult createFromParcel(@NonNull Parcel in) {
385                     return new Builder(in.readDouble(), in.readDouble())
386                             .setAzimuthAngle(in.readDouble())
387                             .setErrorAzimuthAngle(in.readDouble())
388                             .setAltitudeAngle(in.readDouble())
389                             .setErrorAltitudeAngle(in.readDouble())
390                             .setDelaySpreadMeters(in.readDouble())
391                             .setConfidenceLevel(in.readDouble())
392                             .setDetectedAttackLevel(in.readInt())
393                             .setVelocityMetersPerSecond(in.readDouble())
394                             .setMeasurementTimestampNanos(in.readLong())
395                             .build();
396                 }
397 
398                 @Override
399                 public @NonNull DistanceMeasurementResult[] newArray(int size) {
400                     return new DistanceMeasurementResult[size];
401                 }
402             };
403 
404     /**
405      * Builder for {@link DistanceMeasurementResult}.
406      *
407      * @hide
408      */
409     @SystemApi
410     public static final class Builder {
411         private double mMeters = Double.NaN;
412         private double mErrorMeters = Double.NaN;
413         private double mAzimuthAngle = Double.NaN;
414         private double mErrorAzimuthAngle = Double.NaN;
415         private double mAltitudeAngle = Double.NaN;
416         private double mErrorAltitudeAngle = Double.NaN;
417         private double mDelaySpreadMeters = Double.NaN;
418         private double mConfidenceLevel = Double.NaN;
419         private int mDetectedAttackLevel = NADM_UNKNOWN;
420         private double mVelocityMetersPerSecond = Double.NaN;
421         private long mMeasurementTimestampNanos = -1L;
422 
423         /**
424          * Constructor of the Builder.
425          *
426          * @param meters distance in meters
427          * @param errorMeters distance error in meters
428          * @throws IllegalArgumentException if meters is NaN or error is negative or NaN
429          */
Builder( @loatRangefrom = 0.0) double meters, @FloatRange(from = 0.0) double errorMeters)430         public Builder(
431                 @FloatRange(from = 0.0) double meters, @FloatRange(from = 0.0) double errorMeters) {
432             if (Double.isNaN(meters) || meters < 0.0) {
433                 throw new IllegalArgumentException("meters must be >= 0.0 and not NaN: " + meters);
434             }
435             if (Double.isNaN(errorMeters) || errorMeters < 0.0) {
436                 throw new IllegalArgumentException(
437                         "errorMeters must be >= 0.0 and not NaN: " + errorMeters);
438             }
439             mMeters = meters;
440             mErrorMeters = errorMeters;
441         }
442 
443         /**
444          * Set the azimuth angle measurement in degrees.
445          *
446          * @param angle azimuth angle in degrees
447          * @throws IllegalArgumentException if value is invalid
448          * @hide
449          */
450         @SystemApi
451         @NonNull
setAzimuthAngle(@loatRangefrom = 0.0, to = 360.0) double angle)452         public Builder setAzimuthAngle(@FloatRange(from = 0.0, to = 360.0) double angle) {
453             if (angle > 360.0 || angle < 0.0) {
454                 throw new IllegalArgumentException(
455                         "angle must be in the range from 0.0 to 360.0 : " + angle);
456             }
457             mAzimuthAngle = angle;
458             return this;
459         }
460 
461         /**
462          * Set the azimuth angle error in degrees.
463          *
464          * @param angle azimuth angle error in degrees
465          * @throws IllegalArgumentException if value is invalid
466          * @hide
467          */
468         @SystemApi
469         @NonNull
setErrorAzimuthAngle(@loatRangefrom = 0.0, to = 360.0) double angle)470         public Builder setErrorAzimuthAngle(@FloatRange(from = 0.0, to = 360.0) double angle) {
471             if (angle > 360.0 || angle < 0.0) {
472                 throw new IllegalArgumentException(
473                         "error angle must be in the range from 0.0 to 360.0 : " + angle);
474             }
475             mErrorAzimuthAngle = angle;
476             return this;
477         }
478 
479         /**
480          * Set the altitude angle measurement in degrees.
481          *
482          * @param angle altitude angle in degrees
483          * @throws IllegalArgumentException if value is invalid
484          * @hide
485          */
486         @SystemApi
487         @NonNull
setAltitudeAngle(@loatRangefrom = -90.0, to = 90.0) double angle)488         public Builder setAltitudeAngle(@FloatRange(from = -90.0, to = 90.0) double angle) {
489             if (angle > 90.0 || angle < -90.0) {
490                 throw new IllegalArgumentException(
491                         "angle must be in the range from -90.0 to 90.0 : " + angle);
492             }
493             mAltitudeAngle = angle;
494             return this;
495         }
496 
497         /**
498          * Set the altitude angle error in degrees.
499          *
500          * @param angle altitude angle error in degrees
501          * @throws IllegalArgumentException if value is invalid
502          * @hide
503          */
504         @SystemApi
505         @NonNull
setErrorAltitudeAngle(@loatRangefrom = 0.0, to = 180.0) double angle)506         public Builder setErrorAltitudeAngle(@FloatRange(from = 0.0, to = 180.0) double angle) {
507             if (angle > 180.0 || angle < 0.0) {
508                 throw new IllegalArgumentException(
509                         "error angle must be in the range from 0.0 to 180.0 : " + angle);
510             }
511             mErrorAltitudeAngle = angle;
512             return this;
513         }
514 
515         /**
516          * Set the estimated delay spread in meters.
517          *
518          * @param delaySpreadMeters estimated delay spread in meters
519          * @throws IllegalArgumentException if value is invalid
520          * @hide
521          */
522         @SystemApi
523         @NonNull
setDelaySpreadMeters(double delaySpreadMeters)524         public Builder setDelaySpreadMeters(double delaySpreadMeters) {
525             if (delaySpreadMeters < 0.0) {
526                 throw new IllegalArgumentException("delaySpreadMeters must be > 0.0");
527             }
528             mDelaySpreadMeters = delaySpreadMeters;
529             return this;
530         }
531 
532         /**
533          * Set the confidence of estimated distance.
534          *
535          * @param confidenceLevel a normalized value from 0.0 (low confidence) to 1.0 (high
536          *     confidence) representing the confidence of estimated distance
537          * @throws IllegalArgumentException if value is invalid
538          * @hide
539          */
540         @SystemApi
541         @NonNull
setConfidenceLevel( @loatRangefrom = 0.0, to = 1.0) double confidenceLevel)542         public Builder setConfidenceLevel(
543                 @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
544             if (confidenceLevel > 1.0 || confidenceLevel < 0.0) {
545                 throw new IllegalArgumentException(
546                         "error confidenceLevel must be in the range from 0.0 to 100.0 : "
547                                 + confidenceLevel);
548             }
549             mConfidenceLevel = confidenceLevel;
550             return this;
551         }
552 
553         /**
554          * Set the value that represents the chance of being attacked for the measurement.
555          *
556          * @param detectedAttackLevel a value that represents the chance of being attacked for the
557          *     measurement.
558          * @throws IllegalArgumentException if value is invalid
559          * @hide
560          */
561         @SystemApi
562         @NonNull
setDetectedAttackLevel(@adm int detectedAttackLevel)563         public Builder setDetectedAttackLevel(@Nadm int detectedAttackLevel) {
564             switch (detectedAttackLevel) {
565                 case NADM_ATTACK_IS_EXTREMELY_UNLIKELY:
566                 case NADM_ATTACK_IS_VERY_UNLIKELY:
567                 case NADM_ATTACK_IS_UNLIKELY:
568                 case NADM_ATTACK_IS_POSSIBLE:
569                 case NADM_ATTACK_IS_LIKELY:
570                 case NADM_ATTACK_IS_VERY_LIKELY:
571                 case NADM_ATTACK_IS_EXTREMELY_LIKELY:
572                 case NADM_UNKNOWN:
573                     mDetectedAttackLevel = detectedAttackLevel;
574                     break;
575                 default:
576                     throw new IllegalArgumentException("Invalid value " + detectedAttackLevel);
577             }
578             return this;
579         }
580 
581         /**
582          * Set estimated velocity, in the direction of line between two devices, of the moving
583          * object in meters/sec.
584          *
585          * @param velocityMetersPerSecond estimated velocity in meters/sec.
586          * @hide
587          */
588         @SystemApi
589         @NonNull
setVelocityMetersPerSecond(double velocityMetersPerSecond)590         public Builder setVelocityMetersPerSecond(double velocityMetersPerSecond) {
591             mVelocityMetersPerSecond = velocityMetersPerSecond;
592             return this;
593         }
594 
595         /**
596          * Set the elapsed realtime in nanoseconds when the distance measurement occurred
597          *
598          * @param measurementTimestampNanos time the distance measurement occurred
599          * @hide
600          */
601         @FlaggedApi(Flags.FLAG_CHANNEL_SOUNDING_25Q2_APIS)
602         @SystemApi
603         @NonNull
setMeasurementTimestampNanos(long measurementTimestampNanos)604         public Builder setMeasurementTimestampNanos(long measurementTimestampNanos) {
605             mMeasurementTimestampNanos = measurementTimestampNanos;
606             return this;
607         }
608 
609         /**
610          * Builds the {@link DistanceMeasurementResult} object.
611          *
612          * @throws IllegalStateException if meters, error, or confidence are not set
613          * @hide
614          */
615         @SystemApi
616         @NonNull
build()617         public DistanceMeasurementResult build() {
618             return new DistanceMeasurementResult(
619                     mMeters,
620                     mErrorMeters,
621                     mAzimuthAngle,
622                     mErrorAzimuthAngle,
623                     mAltitudeAngle,
624                     mErrorAltitudeAngle,
625                     mDelaySpreadMeters,
626                     mConfidenceLevel,
627                     mDetectedAttackLevel,
628                     mVelocityMetersPerSecond,
629                     mMeasurementTimestampNanos);
630         }
631     }
632 }
633