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