1 /*
2  * Copyright (C) 2017 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.net.wifi.rtt;
18 
19 import android.annotation.ElapsedRealtimeLong;
20 import android.annotation.FlaggedApi;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SuppressLint;
25 import android.annotation.SystemApi;
26 import android.net.MacAddress;
27 import android.net.wifi.OuiKeyedData;
28 import android.net.wifi.ParcelUtil;
29 import android.net.wifi.ScanResult;
30 import android.net.wifi.WifiAnnotations.ChannelWidth;
31 import android.net.wifi.aware.PeerHandle;
32 import android.os.Build;
33 import android.os.Parcel;
34 import android.os.Parcelable;
35 
36 import androidx.annotation.RequiresApi;
37 
38 import com.android.modules.utils.build.SdkLevel;
39 import com.android.wifi.flags.Flags;
40 
41 import java.lang.annotation.Retention;
42 import java.lang.annotation.RetentionPolicy;
43 import java.util.Arrays;
44 import java.util.Collections;
45 import java.util.List;
46 import java.util.Objects;
47 
48 /**
49  * Ranging result for a request started by
50  * {@link WifiRttManager#startRanging(RangingRequest, java.util.concurrent.Executor, RangingResultCallback)}.
51  * Results are returned in {@link RangingResultCallback#onRangingResults(List)}.
52  * <p>
53  * A ranging result is the distance measurement result for a single device specified in the
54  * {@link RangingRequest}.
55  */
56 public final class RangingResult implements Parcelable {
57     private static final String TAG = "RangingResult";
58     private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
59 
60     /** @hide */
61     @IntDef({STATUS_SUCCESS, STATUS_FAIL, STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC})
62     @Retention(RetentionPolicy.SOURCE)
63     public @interface RangeResultStatus {
64     }
65 
66     /**
67      * Individual range request status, {@link #getStatus()}. Indicates ranging operation was
68      * successful and distance value is valid.
69      */
70     public static final int STATUS_SUCCESS = 0;
71 
72     /**
73      * Individual range request status, {@link #getStatus()}. Indicates ranging operation failed
74      * and the distance value is invalid.
75      */
76     public static final int STATUS_FAIL = 1;
77 
78     /**
79      * Individual range request status, {@link #getStatus()}. Indicates that the ranging operation
80      * failed because the specified peer does not support IEEE 802.11mc RTT operations. Support by
81      * an Access Point can be confirmed using
82      * {@link android.net.wifi.ScanResult#is80211mcResponder()}.
83      * <p>
84      * On such a failure, the individual result fields of {@link RangingResult} such as
85      * {@link RangingResult#getDistanceMm()} are invalid.
86      */
87     public static final int STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC = 2;
88 
89     /**
90      * The unspecified value.
91      */
92     public static final int UNSPECIFIED = -1;
93 
94     private final @RangeResultStatus int mStatus;
95     private final MacAddress mMac;
96     private final PeerHandle mPeerHandle;
97     private final int mDistanceMm;
98     private final int mDistanceStdDevMm;
99     private final int mRssi;
100     private final int mNumAttemptedMeasurements;
101     private final int mNumSuccessfulMeasurements;
102     private final byte[] mLci;
103     private final byte[] mLcr;
104     private final ResponderLocation mResponderLocation;
105     private final long mTimestamp;
106     private final boolean mIs80211mcMeasurement;
107     private final int mFrequencyMHz;
108     private final int mPacketBw;
109     private final boolean mIs80211azNtbMeasurement;
110     private final long mNtbMinMeasurementTime;
111     private final long mNtbMaxMeasurementTime;
112     private final int mI2rTxLtfRepetitions;
113     private final int mR2iTxLtfRepetitions;
114     private final int mNumTxSpatialStreams;
115     private final int mNumRxSpatialStreams;
116     private List<OuiKeyedData> mVendorData;
117 
118     /**
119      * Builder class used to construct {@link RangingResult} objects.
120      */
121     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
122     public static final class Builder {
123         private @RangeResultStatus int mStatus = STATUS_FAIL;
124         private MacAddress mMac = null;
125         private PeerHandle mPeerHandle = null;
126         private int mDistanceMm = 0;
127         private int mDistanceStdDevMm = 0;
128         private int mRssi = -127;
129         private int mNumAttemptedMeasurements = 0;
130         private int mNumSuccessfulMeasurements = 0;
131         private byte[] mLci = null;
132         private  byte[] mLcr = null;
133         private ResponderLocation mResponderLocation = null;
134         private long mTimestamp = 0;
135         private boolean mIs80211mcMeasurement = false;
136         private int mFrequencyMHz = UNSPECIFIED;
137         private int mPacketBw = UNSPECIFIED;
138         private boolean mIs80211azNtbMeasurement = false;
139         private long mNtbMinMeasurementTime = UNSPECIFIED;
140         private long mNtbMaxMeasurementTime = UNSPECIFIED;
141         private int mI2rTxLtfRepetitions = UNSPECIFIED;
142         private int mR2iTxLtfRepetitions = UNSPECIFIED;
143         private int mNumTxSpatialStreams = UNSPECIFIED;
144         private int mNumRxSpatialStreams = UNSPECIFIED;
145         private List<OuiKeyedData> mVendorData = Collections.emptyList();
146 
147         /**
148          * Sets the Range result status.
149          *
150          * @param status Ranging result status, if not set defaults to
151          *               {@link #STATUS_FAIL}.
152          * @return The builder to facilitate chaining.
153          */
154         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
155         @NonNull
setStatus(@angeResultStatus int status)156         public Builder setStatus(@RangeResultStatus int status) {
157             mStatus = status;
158             return this;
159         }
160 
161         /**
162          * Sets the MAC address of the ranging result.
163          *
164          * @param macAddress Mac address, if not defaults to null.
165          * @return The builder to facilitate chaining.
166          */
167         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
168         @NonNull
setMacAddress(@ullable MacAddress macAddress)169         public Builder setMacAddress(@Nullable MacAddress macAddress) {
170             mMac = macAddress;
171             return this;
172         }
173 
174 
175         /**
176          * Sets the peer handle. Applicable only for NAN Ranging.
177          *
178          * @param peerHandle Opaque object used to represent a Wi-Fi Aware peer. If not set,
179          *                   defaults to null.
180          * @return The builder to facilitate chaining.
181          */
182         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
183         @NonNull
setPeerHandle(@ullable PeerHandle peerHandle)184         public Builder setPeerHandle(@Nullable PeerHandle peerHandle) {
185             mPeerHandle = peerHandle;
186             return this;
187         }
188 
189         /**
190          * Sets the distance in millimeter.
191          *
192          * @param distanceMm distance. If not set, defaults to 0.
193          * @return The builder to facilitate chaining.
194          */
195         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
196         @NonNull
setDistanceMm(int distanceMm)197         public Builder setDistanceMm(int distanceMm) {
198             mDistanceMm = distanceMm;
199             return this;
200         }
201 
202         /**
203          * Sets the standard deviation of the distance in millimeter.
204          *
205          * @param distanceStdDevMm Standard deviation of the distance measurement. If not set
206          *                         defaults to 0.
207          * @return The builder to facilitate chaining.
208          */
209         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
210         @NonNull
setDistanceStdDevMm(int distanceStdDevMm)211         public Builder setDistanceStdDevMm(int distanceStdDevMm) {
212             mDistanceStdDevMm = distanceStdDevMm;
213             return this;
214         }
215 
216         /**
217          * Sets the average RSSI.
218          *
219          * @param rssi Average RSSI. If not set, defaults to -127.
220          * @return The builder to facilitate chaining.
221          */
222         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
223         @NonNull
setRssi(int rssi)224         public Builder setRssi(int rssi) {
225             mRssi = rssi;
226             return this;
227         }
228 
229         /**
230          * Sets the total number of RTT measurements attempted.
231          *
232          * @param numAttemptedMeasurements Number of attempted measurements. If not set, default
233          *                                 to 0.
234          * @return The builder to facilitate chaining.
235          */
236         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
237         @NonNull
setNumAttemptedMeasurements(int numAttemptedMeasurements)238         public Builder setNumAttemptedMeasurements(int numAttemptedMeasurements) {
239             mNumAttemptedMeasurements = numAttemptedMeasurements;
240             return this;
241         }
242 
243         /**
244          * Sets the total number of successful RTT measurements.
245          *
246          * @param numSuccessfulMeasurements Number of successful measurements. If not set, default
247          *                                 to 0.
248          * @return The builder to facilitate chaining.
249          */
250         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
251         @NonNull
setNumSuccessfulMeasurements(int numSuccessfulMeasurements)252         public Builder setNumSuccessfulMeasurements(int numSuccessfulMeasurements) {
253             mNumSuccessfulMeasurements = numSuccessfulMeasurements;
254             return this;
255         }
256 
257         /**
258          * Sets the Location Configuration Information (LCI).
259          *
260          * LCI provides data about the access point's (AP) physical location, such as its
261          * latitude, longitude, and altitude. The format is specified in the IEEE 802.11-2016
262          * specifications, section 9.4.2.22.10.
263          *
264          * @param lci Location configuration information. If not set, defaults to null.
265          * @return The builder to facilitate chaining.
266          */
267         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
268         @NonNull
setLci(@ullable byte[] lci)269         public Builder setLci(@Nullable byte[] lci) {
270             mLci = lci;
271             return this;
272         }
273 
274         /**
275          * Sets the Location Civic Report (LCR).
276          *
277          * LCR provides additional details about the AP's location in a human-readable format,
278          * such as the street address, building name, or floor number. This can be helpful for
279          * users to understand the context of their location within a building or complex.
280          *
281          * The format is
282          * specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.13.
283          *
284          * @param lcr Location civic report. If not set, defaults to null.
285          * @return The builder to facilitate chaining.
286          */
287         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
288         @NonNull
setLcr(@ullable byte[] lcr)289         public Builder setLcr(@Nullable byte[] lcr) {
290             mLcr = lcr;
291             return this;
292         }
293 
294         /**
295          * Sets Responder Location.
296          *
297          * ResponderLocation is both a Location Configuration Information (LCI) decoder and a
298          * Location Civic Report (LCR) decoder for information received from a Wi-Fi Access Point
299          * (AP) during Wi-Fi RTT ranging process.
300          *
301          * @param responderLocation Responder location. If not set, defaults to null.
302          * @return The builder to facilitate chaining.
303          */
304         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
305         @NonNull
setUnverifiedResponderLocation( @ullable ResponderLocation responderLocation)306         public Builder setUnverifiedResponderLocation(
307                 @Nullable ResponderLocation responderLocation) {
308             mResponderLocation = responderLocation;
309             return this;
310         }
311 
312         /**
313          * Sets the time stamp at which the ranging operation was performed.
314          *
315          * The timestamp is in milliseconds since boot, including time spent in sleep,
316          * corresponding to values provided by {@link android.os.SystemClock#elapsedRealtime()}.
317          *
318          * @param timestamp time stamp in milliseconds. If not set, default to 0.
319          * @return The builder to facilitate chaining.
320          */
321         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
322         @NonNull
setRangingTimestampMillis(@lapsedRealtimeLong long timestamp)323         public Builder setRangingTimestampMillis(@ElapsedRealtimeLong long timestamp) {
324             mTimestamp = timestamp;
325             return this;
326         }
327 
328 
329         /**
330          * Sets whether the ranging measurement was performed using IEEE 802.11mc ranging method.
331          * If {@link #set80211mcMeasurement(boolean)} is set as false and
332          * {@link #set80211azNtbMeasurement(boolean)} is also set as false, ranging measurement was
333          * performed using one-side RTT. If not set, default to false.
334          *
335          * @param is80211mcMeasurement true for IEEE 802.11mc measure, otherwise false.
336          * @return The builder to facilitate chaining.
337          */
338         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
339         @NonNull
set80211mcMeasurement(boolean is80211mcMeasurement)340         public Builder set80211mcMeasurement(boolean is80211mcMeasurement) {
341             mIs80211mcMeasurement = is80211mcMeasurement;
342             return this;
343         }
344 
345         /**
346          * Sets the center frequency of the primary 20 MHz frequency (in MHz) of the channel over
347          * which the measurement frames are sent. If not set, default to
348          * {@link RangingResult#UNSPECIFIED}
349          *
350          * @param frequencyMHz Frequency.
351          * @return The builder to facilitate chaining.
352          */
353         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
354         @NonNull
setMeasurementChannelFrequencyMHz(int frequencyMHz)355         public Builder setMeasurementChannelFrequencyMHz(int frequencyMHz) {
356             mFrequencyMHz = frequencyMHz;
357             return this;
358         }
359 
360         /**
361          * Sets the bandwidth used to transmit the RTT measurement frame. If not set, default to
362          * {@link RangingResult#UNSPECIFIED}.
363          *
364          * @param measurementBandwidth Measurement bandwidth.
365          * @return The builder to facilitate chaining.
366          */
367         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
368         @NonNull
setMeasurementBandwidth(@hannelWidth int measurementBandwidth)369         public Builder setMeasurementBandwidth(@ChannelWidth int measurementBandwidth) {
370             mPacketBw = measurementBandwidth;
371             return this;
372         }
373 
374         /**
375          * Sets whether the ranging measurement was performed using IEEE 802.11az non-trigger
376          * ranging method. If {@link #set80211azNtbMeasurement(boolean)} is set as false and
377          * {@link #set80211mcMeasurement(boolean)} is also set as false, ranging measurement was
378          * performed using one-side RTT. If not set defaults to false.
379          *
380          * @param is80211azNtbMeasurement true for IEEE 802.11az non-trigger based measurement,
381          *                                otherwise false.
382          * @return The builder to facilitate chaining.
383          */
384         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
385         @NonNull
set80211azNtbMeasurement(boolean is80211azNtbMeasurement)386         public Builder set80211azNtbMeasurement(boolean is80211azNtbMeasurement) {
387             mIs80211azNtbMeasurement = is80211azNtbMeasurement;
388             return this;
389         }
390 
391         /**
392          * Sets minimum time between measurements in microseconds for IEEE 802.11az non-trigger
393          * based ranging.  If not set, defaults to {@link RangingResult#UNSPECIFIED}.
394          *
395          * @param ntbMinMeasurementTime non-trigger based ranging minimum measurement time.
396          * @return The builder to facilitate chaining.
397          */
398         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
399         @NonNull
setMinTimeBetweenNtbMeasurementsMicros(long ntbMinMeasurementTime)400         public Builder setMinTimeBetweenNtbMeasurementsMicros(long ntbMinMeasurementTime) {
401             mNtbMinMeasurementTime = ntbMinMeasurementTime;
402             return this;
403         }
404 
405         /**
406          * Sets maximum time between measurements in microseconds for IEEE 802.11az non-trigger
407          * based ranging. If not set, defaults to {@link RangingResult#UNSPECIFIED}.
408          *
409          * @param ntbMaxMeasurementTime non-trigger based ranging maximum measurement time.
410          * @return The builder to facilitate chaining.
411          */
412         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
413         @NonNull
setMaxTimeBetweenNtbMeasurementsMicros(long ntbMaxMeasurementTime)414         public Builder setMaxTimeBetweenNtbMeasurementsMicros(long ntbMaxMeasurementTime) {
415             mNtbMaxMeasurementTime = ntbMaxMeasurementTime;
416             return this;
417         }
418 
419         /**
420          * Sets LTF repetitions that the initiator station used in the preamble. If not set,
421          * defaults to {@link RangingResult#UNSPECIFIED}.
422          *
423          * @param i2rTxLtfRepetitions LFT repetition count.
424          * @return The builder to facilitate chaining.
425          */
426         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
427         @NonNull
set80211azInitiatorTxLtfRepetitionsCount(int i2rTxLtfRepetitions)428         public Builder set80211azInitiatorTxLtfRepetitionsCount(int i2rTxLtfRepetitions) {
429             mI2rTxLtfRepetitions = i2rTxLtfRepetitions;
430             return this;
431         }
432 
433         /**
434          * Sets LTF repetitions that the responder station used in the preamble. If not set,
435          * defaults to {@link RangingResult#UNSPECIFIED}.
436          *
437          * @param r2iTxLtfRepetitions LFT repetition count.
438          * @return The builder to facilitate chaining.
439          */
440         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
441         @NonNull
set80211azResponderTxLtfRepetitionsCount(int r2iTxLtfRepetitions)442         public Builder set80211azResponderTxLtfRepetitionsCount(int r2iTxLtfRepetitions) {
443             mR2iTxLtfRepetitions = r2iTxLtfRepetitions;
444             return this;
445         }
446 
447         /**
448          * Sets number of transmit spatial streams that the initiator station used for the
449          * ranging result. If not set, defaults to {@link RangingResult#UNSPECIFIED}.
450          *
451          * @param numTxSpatialStreams Number of transmit spatial streams.
452          * @return The builder to facilitate chaining.
453          */
454         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
455         @NonNull
set80211azNumberOfTxSpatialStreams(int numTxSpatialStreams)456         public Builder set80211azNumberOfTxSpatialStreams(int numTxSpatialStreams) {
457             mNumTxSpatialStreams = numTxSpatialStreams;
458             return this;
459         }
460 
461         /**
462          * Sets number of receive spatial streams that the initiator station used for the ranging
463          * result. If not set, defaults to {@link RangingResult#UNSPECIFIED}.
464          *
465          * @param numRxSpatialStreams Number of receive spatial streams.
466          * @return The builder to facilitate chaining.
467          */
468         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
469         @NonNull
set80211azNumberOfRxSpatialStreams(int numRxSpatialStreams)470         public Builder set80211azNumberOfRxSpatialStreams(int numRxSpatialStreams) {
471             mNumRxSpatialStreams = numRxSpatialStreams;
472             return this;
473         }
474 
475         /**
476          * Set additional vendor-provided configuration data.
477          *
478          * @param vendorData List of {@link android.net.wifi.OuiKeyedData} containing the
479          *                   vendor-provided configuration data. Note that multiple elements with
480          *                   the same OUI are allowed.
481          * @hide
482          */
483         @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
484         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
485         @SystemApi
486         @NonNull
setVendorData(@onNull List<OuiKeyedData> vendorData)487         public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) {
488             if (!SdkLevel.isAtLeastV()) {
489                 throw new UnsupportedOperationException();
490             }
491             if (vendorData == null) {
492                 throw new IllegalArgumentException("setVendorData received a null value");
493             }
494             mVendorData = vendorData;
495             return this;
496         }
497 
498         /**
499          * Build {@link RangingResult}
500          * @return an instance of {@link RangingResult}
501          */
502         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
503         @NonNull
build()504         public RangingResult build() {
505             if (mMac == null && mPeerHandle == null) {
506                 throw new IllegalArgumentException("Either MAC address or Peer handle is needed");
507             }
508             if (mIs80211azNtbMeasurement && mIs80211mcMeasurement) {
509                 throw new IllegalArgumentException(
510                         "A ranging result cannot use both IEEE 802.11mc and IEEE 802.11az "
511                                 + "measurements simultaneously");
512             }
513             return new RangingResult(this);
514         }
515     }
516 
517     /** @hide */
RangingResult(Builder builder)518     private RangingResult(Builder builder) {
519         mStatus = builder.mStatus;
520         mMac = builder.mMac;
521         mPeerHandle = builder.mPeerHandle;
522         mDistanceMm = builder.mDistanceMm;
523         mDistanceStdDevMm = builder.mDistanceStdDevMm;
524         mRssi = builder.mRssi;
525         mNumAttemptedMeasurements = builder.mNumAttemptedMeasurements;
526         mNumSuccessfulMeasurements = builder.mNumSuccessfulMeasurements;
527         mLci = (builder.mLci == null) ? EMPTY_BYTE_ARRAY : builder.mLci;
528         mLcr = (builder.mLcr == null) ? EMPTY_BYTE_ARRAY : builder.mLcr;
529         mResponderLocation = builder.mResponderLocation;
530         mTimestamp = builder.mTimestamp;
531         mIs80211mcMeasurement = builder.mIs80211mcMeasurement;
532         mFrequencyMHz = builder.mFrequencyMHz;
533         mPacketBw = builder.mPacketBw;
534         mIs80211azNtbMeasurement = builder.mIs80211azNtbMeasurement;
535         mNtbMinMeasurementTime = builder.mNtbMinMeasurementTime;
536         mNtbMaxMeasurementTime = builder.mNtbMaxMeasurementTime;
537         mI2rTxLtfRepetitions = builder.mI2rTxLtfRepetitions;
538         mR2iTxLtfRepetitions = builder.mR2iTxLtfRepetitions;
539         mNumRxSpatialStreams = builder.mNumRxSpatialStreams;
540         mNumTxSpatialStreams = builder.mNumTxSpatialStreams;
541         mVendorData = builder.mVendorData;
542     }
543 
544     /**
545      * @return The status of ranging measurement: {@link #STATUS_SUCCESS} in case of success, and
546      * {@link #STATUS_FAIL} in case of failure.
547      */
548     @RangeResultStatus
getStatus()549     public int getStatus() {
550         return mStatus;
551     }
552 
553     /**
554      * @return The MAC address of the device whose range measurement was requested. Will correspond
555      * to the MAC address of the device in the {@link RangingRequest}.
556      * <p>
557      * Will return a {@code null} for results corresponding to requests issued using a {@code
558      * PeerHandle}, i.e. using the {@link RangingRequest.Builder#addWifiAwarePeer(PeerHandle)} API.
559      */
560     @Nullable
getMacAddress()561     public MacAddress getMacAddress() {
562         return mMac;
563     }
564 
565     /**
566      * @return The PeerHandle of the device whose reange measurement was requested. Will correspond
567      * to the PeerHandle of the devices requested using
568      * {@link RangingRequest.Builder#addWifiAwarePeer(PeerHandle)}.
569      * <p>
570      * Will return a {@code null} for results corresponding to requests issued using a MAC address.
571      */
getPeerHandle()572     @Nullable public PeerHandle getPeerHandle() {
573         return mPeerHandle;
574     }
575 
576     /**
577      * @return The distance (in mm) to the device specified by {@link #getMacAddress()} or
578      * {@link #getPeerHandle()}.
579      * <p>
580      * Note: the measured distance may be negative for very close devices.
581      * <p>
582      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
583      * exception.
584      */
getDistanceMm()585     public int getDistanceMm() {
586         if (mStatus != STATUS_SUCCESS) {
587             throw new IllegalStateException(
588                     "getDistanceMm(): invoked on an invalid result: getStatus()=" + mStatus);
589         }
590         return mDistanceMm;
591     }
592 
593     /**
594      * @return The standard deviation of the measured distance (in mm) to the device specified by
595      * {@link #getMacAddress()} or {@link #getPeerHandle()}. The standard deviation is calculated
596      * over the measurements executed in a single RTT burst. The number of measurements is returned
597      * by {@link #getNumSuccessfulMeasurements()} - 0 successful measurements indicate that the
598      * standard deviation is not valid (a valid standard deviation requires at least 2 data points).
599      * <p>
600      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
601      * exception.
602      */
getDistanceStdDevMm()603     public int getDistanceStdDevMm() {
604         if (mStatus != STATUS_SUCCESS) {
605             throw new IllegalStateException(
606                     "getDistanceStdDevMm(): invoked on an invalid result: getStatus()=" + mStatus);
607         }
608         return mDistanceStdDevMm;
609     }
610 
611     /**
612      * @return The average RSSI, in units of dBm, observed during the RTT measurement.
613      * <p>
614      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
615      * exception.
616      */
getRssi()617     public int getRssi() {
618         if (mStatus != STATUS_SUCCESS) {
619             throw new IllegalStateException(
620                     "getRssi(): invoked on an invalid result: getStatus()=" + mStatus);
621         }
622         return mRssi;
623     }
624 
625     /**
626      * @return The number of attempted measurements used in the RTT exchange resulting in this set
627      * of results. The number of successful measurements is returned by
628      * {@link #getNumSuccessfulMeasurements()} which at most, if there are no errors, will be 1
629      * less than the number of attempted measurements.
630      * <p>
631      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
632      * exception. If the value is 0, it should be interpreted as no information available, which may
633      * occur for one-sided RTT measurements. Instead {@link RangingRequest#getRttBurstSize()}
634      * should be used instead.
635      */
getNumAttemptedMeasurements()636     public int getNumAttemptedMeasurements() {
637         if (mStatus != STATUS_SUCCESS) {
638             throw new IllegalStateException(
639                     "getNumAttemptedMeasurements(): invoked on an invalid result: getStatus()="
640                             + mStatus);
641         }
642         return mNumAttemptedMeasurements;
643     }
644 
645     /**
646      * @return The number of successful measurements used to calculate the distance and standard
647      * deviation. If the number of successful measurements if 1 then then standard deviation,
648      * returned by {@link #getDistanceStdDevMm()}, is not valid (a 0 is returned for the standard
649      * deviation).
650      * <p>
651      * The total number of measurement attempts is returned by
652      * {@link #getNumAttemptedMeasurements()}. The number of successful measurements will be at
653      * most 1 less then the number of attempted measurements.
654      * <p>
655      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
656      * exception.
657      */
getNumSuccessfulMeasurements()658     public int getNumSuccessfulMeasurements() {
659         if (mStatus != STATUS_SUCCESS) {
660             throw new IllegalStateException(
661                     "getNumSuccessfulMeasurements(): invoked on an invalid result: getStatus()="
662                             + mStatus);
663         }
664         return mNumSuccessfulMeasurements;
665     }
666 
667     /**
668      * @return The unverified responder location represented as {@link ResponderLocation} which
669      * captures location information the responder is programmed to broadcast. The responder
670      * location is referred to as unverified, because we are relying on the device/site
671      * administrator to correctly configure its location data.
672      * <p>
673      * Will return a {@code null} when the location information cannot be parsed.
674      * <p>
675      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
676      * exception.
677      */
678     @Nullable
getUnverifiedResponderLocation()679     public ResponderLocation getUnverifiedResponderLocation() {
680         if (mStatus != STATUS_SUCCESS) {
681             throw new IllegalStateException(
682                     "getUnverifiedResponderLocation(): invoked on an invalid result: getStatus()="
683                             + mStatus);
684         }
685         return mResponderLocation;
686     }
687 
688     /**
689      * @return The Location Configuration Information (LCI) as self-reported by the peer. The format
690      * is specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.10.
691      * <p>
692      * Note: the information is NOT validated - use with caution. Consider validating it with
693      * other sources of information before using it.
694      */
695     @SuppressLint("UnflaggedApi") // Flagging API promotion from @SystemApi to public not supported
696     @NonNull
getLci()697     public byte[] getLci() {
698         if (mStatus != STATUS_SUCCESS) {
699             throw new IllegalStateException(
700                     "getLci(): invoked on an invalid result: getStatus()=" + mStatus);
701         }
702         return mLci;
703     }
704 
705     /**
706      * @return The Location Civic report (LCR) as self-reported by the peer. The format
707      * is specified in the IEEE 802.11-2016 specifications, section 9.4.2.22.13.
708      * <p>
709      * Note: the information is NOT validated - use with caution. Consider validating it with
710      * other sources of information before using it.
711      */
712     @SuppressLint("UnflaggedApi") // Flagging API promotion from @SystemApi to public not supported
713     @NonNull
getLcr()714     public byte[] getLcr() {
715         if (mStatus != STATUS_SUCCESS) {
716             throw new IllegalStateException(
717                     "getReportedLocationCivic(): invoked on an invalid result: getStatus()="
718                             + mStatus);
719         }
720         return mLcr;
721     }
722 
723     /**
724      * @return The timestamp at which the ranging operation was performed. The timestamp is in
725      * milliseconds since boot, including time spent in sleep, corresponding to values provided by
726      * {@link android.os.SystemClock#elapsedRealtime()}.
727      * <p>
728      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
729      * exception.
730      */
getRangingTimestampMillis()731     public long getRangingTimestampMillis() {
732         if (mStatus != STATUS_SUCCESS) {
733             throw new IllegalStateException(
734                     "getRangingTimestampMillis(): invoked on an invalid result: getStatus()="
735                             + mStatus);
736         }
737         return mTimestamp;
738     }
739 
740     /**
741      * @return The result is true if the IEEE 802.11mc protocol was used. If the result is false,
742      * and {@link #is80211azNtbMeasurement()} is also false a one-side RTT result is provided
743      * which does not subtract the turnaround time at the responder.
744      * <p>
745      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
746      * exception.
747      */
is80211mcMeasurement()748     public boolean is80211mcMeasurement() {
749         if (mStatus != STATUS_SUCCESS) {
750             throw new IllegalStateException(
751                     "is80211mcMeasurementResult(): invoked on an invalid result: getStatus()="
752                             + mStatus);
753         }
754         return mIs80211mcMeasurement;
755     }
756 
757     /**
758      * @return The result is true if the IEEE 802.11az non-trigger based protocol was used. If the
759      * result is false, and {@link #is80211mcMeasurement()} is also false a one-side RTT result
760      * is provided which does not subtract the turnaround time at the responder.
761      * <p>.
762      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
763      * exception.
764      */
765     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
is80211azNtbMeasurement()766     public boolean is80211azNtbMeasurement() {
767         if (mStatus != STATUS_SUCCESS) {
768             throw new IllegalStateException(
769                     "is80211azNtbMeasurement(): invoked on an invalid result: getStatus()="
770                             + mStatus);
771         }
772         return mIs80211azNtbMeasurement;
773     }
774 
775     /**
776      * Gets minimum time between measurements in microseconds for IEEE 802.11az non-trigger based
777      * ranging.
778      *
779      * The next 11az ranging measurement request must be invoked after the minimum time from the
780      * last measurement time {@link #getRangingTimestampMillis()} for the peer. Otherwise, cached
781      * ranging result will be returned for the peer.
782      */
783     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
getMinTimeBetweenNtbMeasurementsMicros()784     public long getMinTimeBetweenNtbMeasurementsMicros() {
785         return mNtbMinMeasurementTime;
786     }
787 
788     /**
789      * Gets maximum time between measurements in microseconds for IEEE 802.11az non-trigger based
790      * ranging.
791      *
792      * The next 11az ranging request needs to be invoked before the maximum time from the last
793      * measurement time {@link #getRangingTimestampMillis()}. Otherwise, the non-trigger based
794      * ranging session will be terminated and a new ranging negotiation will happen with
795      * the responding station.
796      */
797     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
getMaxTimeBetweenNtbMeasurementsMicros()798     public long getMaxTimeBetweenNtbMeasurementsMicros() {
799         return mNtbMaxMeasurementTime;
800     }
801 
802     /**
803      * Gets LTF repetitions that the responder station (RSTA) used in the preamble of the
804      * responder to initiator (I2R) null data PPDU (NDP) for this result.
805      *
806      * LTF repetitions is the multiple transmissions of HE-LTF symbols in an HE ranging NDP. An
807      * HE-LTF repetition value of 1 indicates no repetitions.
808      *
809      * @return LTF repetitions count
810      */
811     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
get80211azResponderTxLtfRepetitionsCount()812     public int get80211azResponderTxLtfRepetitionsCount() {
813         return mR2iTxLtfRepetitions;
814     }
815 
816     /**
817      * Gets LTF repetitions that the initiator station (ISTA) used in the preamble of the
818      * initiator to responder (I2R) null data PPDU (NDP) for this result.
819      *
820      * LTF repetitions is the multiple transmissions of HE-LTF symbols in an HE ranging NDP. An
821      * HE-LTF repetition value of 1 indicates no repetitions.
822      *
823      * @return LTF repetitions count
824      */
825     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
get80211azInitiatorTxLtfRepetitionsCount()826     public int get80211azInitiatorTxLtfRepetitionsCount() {
827         return mI2rTxLtfRepetitions;
828     }
829 
830     /**
831      * Gets number of transmit spatial streams that the initiator station (ISTA) used for the
832      * initiator to responder (I2R) null data PPDU (NDP) for this result.
833      *
834      * @return Number of spatial streams
835      */
836     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
get80211azNumberOfTxSpatialStreams()837     public int get80211azNumberOfTxSpatialStreams() {
838         return mNumTxSpatialStreams;
839     }
840 
841     /**
842      * Gets number of receive spatial streams that the initiator station (ISTA) used for the
843      * initiator to responder (I2R) null data PPDU (NDP) for this result.
844      *
845      * @return Number of spatial streams
846      */
847     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
get80211azNumberOfRxSpatialStreams()848     public int get80211azNumberOfRxSpatialStreams() {
849         return mNumRxSpatialStreams;
850     }
851 
852     /**
853      * The center frequency of the primary 20 MHz frequency (in MHz) of the channel over
854      * which the measurement frames are sent.
855      * @return center frequency in Mhz of the channel if available, otherwise {@link #UNSPECIFIED}
856      * is returned.
857      * <p>
858      * @throws IllegalStateException if {@link #getStatus()} does not return
859      * {@link #STATUS_SUCCESS}.
860      */
getMeasurementChannelFrequencyMHz()861     public int getMeasurementChannelFrequencyMHz() {
862         if (mStatus != STATUS_SUCCESS) {
863             throw new IllegalStateException(
864                     "getMeasurementChannelFrequencyMHz():"
865                     + " invoked on an invalid result: getStatus()= " + mStatus);
866         }
867         return mFrequencyMHz;
868     }
869 
870     /**
871      * The bandwidth used to transmit the RTT measurement frame.
872      * @return one of {@link ScanResult#CHANNEL_WIDTH_20MHZ},
873      * {@link ScanResult#CHANNEL_WIDTH_40MHZ},
874      * {@link ScanResult#CHANNEL_WIDTH_80MHZ}, {@link ScanResult#CHANNEL_WIDTH_160MHZ},
875      * {@link ScanResult #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link ScanResult #CHANNEL_WIDTH_320MHZ}
876      * if available, otherwise {@link #UNSPECIFIED} is returned.
877      * <p>
878      * @throws IllegalStateException if {@link #getStatus()} does not return
879      * {@link #STATUS_SUCCESS}.
880      */
getMeasurementBandwidth()881     public @ChannelWidth int getMeasurementBandwidth() {
882         if (mStatus != STATUS_SUCCESS) {
883             throw new IllegalStateException(
884                     "getMeasurementBandwidth(): invoked on an invalid result: getStatus()="
885                             + mStatus);
886         }
887         return mPacketBw;
888     }
889 
890     /**
891      * Get the vendor-provided configuration data, if it exists.
892      *
893      * @return Vendor configuration data, or empty list if it does not exist.
894      * @hide
895      */
896     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
897     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
898     @SystemApi
899     @NonNull
getVendorData()900     public List<OuiKeyedData> getVendorData() {
901         if (!SdkLevel.isAtLeastV()) {
902             throw new UnsupportedOperationException();
903         }
904         return mVendorData;
905     }
906 
907     @Override
describeContents()908     public int describeContents() {
909         return 0;
910     }
911 
912     @Override
writeToParcel(Parcel dest, int flags)913     public void writeToParcel(Parcel dest, int flags) {
914         dest.writeInt(mStatus);
915         if (mMac == null) {
916             dest.writeBoolean(false);
917         } else {
918             dest.writeBoolean(true);
919             mMac.writeToParcel(dest, flags);
920         }
921         if (mPeerHandle == null) {
922             dest.writeBoolean(false);
923         } else {
924             dest.writeBoolean(true);
925             dest.writeInt(mPeerHandle.peerId);
926         }
927         dest.writeInt(mDistanceMm);
928         dest.writeInt(mDistanceStdDevMm);
929         dest.writeInt(mRssi);
930         dest.writeInt(mNumAttemptedMeasurements);
931         dest.writeInt(mNumSuccessfulMeasurements);
932         dest.writeByteArray(mLci);
933         dest.writeByteArray(mLcr);
934         dest.writeParcelable(mResponderLocation, flags);
935         dest.writeLong(mTimestamp);
936         dest.writeBoolean(mIs80211mcMeasurement);
937         dest.writeInt(mFrequencyMHz);
938         dest.writeInt(mPacketBw);
939         dest.writeBoolean(mIs80211azNtbMeasurement);
940         dest.writeLong(mNtbMinMeasurementTime);
941         dest.writeLong(mNtbMaxMeasurementTime);
942         dest.writeInt(mI2rTxLtfRepetitions);
943         dest.writeInt(mR2iTxLtfRepetitions);
944         dest.writeInt(mNumTxSpatialStreams);
945         dest.writeInt(mNumRxSpatialStreams);
946         if (SdkLevel.isAtLeastV()) {
947             dest.writeList(mVendorData);
948         }
949     }
950 
951     public static final @android.annotation.NonNull Creator<RangingResult> CREATOR =
952             new Creator<RangingResult>() {
953                 @Override
954                 public RangingResult[] newArray(int size) {
955                     return new RangingResult[size];
956                 }
957 
958                 @Override
959                 public RangingResult createFromParcel(Parcel in) {
960                     RangingResult.Builder builder = new Builder()
961                             .setStatus(in.readInt())
962                             .setMacAddress(
963                                     in.readBoolean() ? MacAddress.CREATOR.createFromParcel(in)
964                                             : null)
965                             .setPeerHandle(in.readBoolean() ? new PeerHandle(in.readInt()) : null)
966                             .setDistanceMm(in.readInt())
967                             .setDistanceStdDevMm(in.readInt())
968                             .setRssi(in.readInt())
969                             .setNumAttemptedMeasurements(in.readInt())
970                             .setNumSuccessfulMeasurements(in.readInt())
971                             .setLci(in.createByteArray())
972                             .setLcr(in.createByteArray())
973                             .setUnverifiedResponderLocation(
974                                     in.readParcelable(this.getClass().getClassLoader()))
975                             .setRangingTimestampMillis(in.readLong())
976                             .set80211mcMeasurement(in.readBoolean())
977                             .setMeasurementChannelFrequencyMHz(in.readInt())
978                             .setMeasurementBandwidth(in.readInt())
979                             .set80211azNtbMeasurement(in.readBoolean())
980                             .setMinTimeBetweenNtbMeasurementsMicros(in.readLong())
981                             .setMaxTimeBetweenNtbMeasurementsMicros(in.readLong())
982                             .set80211azInitiatorTxLtfRepetitionsCount(in.readInt())
983                             .set80211azResponderTxLtfRepetitionsCount(in.readInt())
984                             .set80211azNumberOfTxSpatialStreams(in.readInt())
985                             .set80211azNumberOfRxSpatialStreams(in.readInt());
986                     if (SdkLevel.isAtLeastV()) {
987                         builder.setVendorData(ParcelUtil.readOuiKeyedDataList(in));
988                     }
989                     return builder.build();
990                 }
991             };
992 
993     /** @hide */
994     @Override
toString()995     public String toString() {
996         return new StringBuilder("RangingResult: [status=").append(mStatus)
997                 .append(", mac=").append(mMac)
998                 .append(", peerHandle=").append(
999                         mPeerHandle == null ? "<null>" : mPeerHandle.peerId)
1000                 .append(", distanceMm=").append(mDistanceMm)
1001                 .append(", distanceStdDevMm=").append(mDistanceStdDevMm)
1002                 .append(", rssi=").append(mRssi)
1003                 .append(", numAttemptedMeasurements=").append(mNumAttemptedMeasurements)
1004                 .append(", numSuccessfulMeasurements=").append(mNumSuccessfulMeasurements)
1005                 .append(", lci=").append(Arrays.toString(mLci))
1006                 .append(", lcr=").append(Arrays.toString(mLcr))
1007                 .append(", responderLocation=").append(mResponderLocation)
1008                 .append(", timestamp=").append(mTimestamp).append(", is80211mcMeasurement=")
1009                 .append(mIs80211mcMeasurement)
1010                 .append(", frequencyMHz=").append(mFrequencyMHz)
1011                 .append(", packetBw=").append(mPacketBw)
1012                 .append("is80211azNtbMeasurement").append(mIs80211azNtbMeasurement)
1013                 .append("ntbMinMeasurementTime").append(mNtbMinMeasurementTime)
1014                 .append("ntbMaxMeasurementTime").append(mNtbMaxMeasurementTime)
1015                 .append("i2rTxLtfRepetitions").append(mI2rTxLtfRepetitions)
1016                 .append("r2iTxLtfRepetitions").append(mR2iTxLtfRepetitions)
1017                 .append("txSpatialStreams").append(mNumTxSpatialStreams)
1018                 .append("rxSpatialStreams").append(mNumRxSpatialStreams)
1019                 .append(", vendorData=").append(mVendorData)
1020                 .append("]").toString();
1021     }
1022 
1023     @Override
equals(Object o)1024     public boolean equals(Object o) {
1025         if (this == o) {
1026             return true;
1027         }
1028 
1029         if (!(o instanceof RangingResult)) {
1030             return false;
1031         }
1032 
1033         RangingResult lhs = (RangingResult) o;
1034 
1035         return mStatus == lhs.mStatus && Objects.equals(mMac, lhs.mMac) && Objects.equals(
1036                 mPeerHandle, lhs.mPeerHandle) && mDistanceMm == lhs.mDistanceMm
1037                 && mDistanceStdDevMm == lhs.mDistanceStdDevMm && mRssi == lhs.mRssi
1038                 && mNumAttemptedMeasurements == lhs.mNumAttemptedMeasurements
1039                 && mNumSuccessfulMeasurements == lhs.mNumSuccessfulMeasurements
1040                 && Arrays.equals(mLci, lhs.mLci) && Arrays.equals(mLcr, lhs.mLcr)
1041                 && mTimestamp == lhs.mTimestamp
1042                 && mIs80211mcMeasurement == lhs.mIs80211mcMeasurement
1043                 && Objects.equals(mResponderLocation, lhs.mResponderLocation)
1044                 && mFrequencyMHz == lhs.mFrequencyMHz
1045                 && mPacketBw == lhs.mPacketBw
1046                 && mIs80211azNtbMeasurement == lhs.mIs80211azNtbMeasurement
1047                 && mNtbMinMeasurementTime == lhs.mNtbMinMeasurementTime
1048                 && mNtbMaxMeasurementTime == lhs.mNtbMaxMeasurementTime
1049                 && mI2rTxLtfRepetitions == lhs.mI2rTxLtfRepetitions
1050                 && mR2iTxLtfRepetitions == lhs.mR2iTxLtfRepetitions
1051                 && mNumTxSpatialStreams == lhs.mNumTxSpatialStreams
1052                 && mNumRxSpatialStreams == lhs.mNumRxSpatialStreams
1053                 && Objects.equals(mVendorData, lhs.mVendorData);
1054     }
1055 
1056     @Override
hashCode()1057     public int hashCode() {
1058         return Objects.hash(mStatus, mMac, mPeerHandle, mDistanceMm, mDistanceStdDevMm, mRssi,
1059                 mNumAttemptedMeasurements, mNumSuccessfulMeasurements, Arrays.hashCode(mLci),
1060                 Arrays.hashCode(mLcr), mResponderLocation, mTimestamp, mIs80211mcMeasurement,
1061                 mFrequencyMHz, mPacketBw, mIs80211azNtbMeasurement, mNtbMinMeasurementTime,
1062                 mNtbMaxMeasurementTime, mI2rTxLtfRepetitions, mR2iTxLtfRepetitions,
1063                 mNumTxSpatialStreams, mR2iTxLtfRepetitions, mVendorData);
1064     }
1065 }
1066