1 /* 2 * Copyright (C) 2021 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.nearby; 18 19 import android.annotation.IntRange; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.bluetooth.le.ScanRecord; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 26 import java.util.Arrays; 27 import java.util.Objects; 28 29 /** 30 * A data class representing scan result from Nearby Service. Scan result can come from multiple 31 * mediums like BLE, Wi-Fi Aware, and etc. A scan result consists of An encapsulation of various 32 * parameters for requesting nearby scans. 33 * 34 * <p>All scan results generated through {@link NearbyManager} are guaranteed to have a valid 35 * medium, identifier, timestamp (both UTC time and elapsed real-time since boot), and accuracy. All 36 * other parameters are optional. 37 * 38 * @hide 39 */ 40 public final class NearbyDeviceParcelable implements Parcelable { 41 42 /** Used to read a NearbyDeviceParcelable from a Parcel. */ 43 @NonNull 44 public static final Creator<NearbyDeviceParcelable> CREATOR = 45 new Creator<NearbyDeviceParcelable>() { 46 @Override 47 public NearbyDeviceParcelable createFromParcel(Parcel in) { 48 Builder builder = new Builder(); 49 builder.setScanType(in.readInt()); 50 if (in.readInt() == 1) { 51 builder.setName(in.readString()); 52 } 53 builder.setMedium(in.readInt()); 54 builder.setTxPower(in.readInt()); 55 builder.setRssi(in.readInt()); 56 builder.setAction(in.readInt()); 57 builder.setPublicCredential( 58 in.readParcelable( 59 PublicCredential.class.getClassLoader(), 60 PublicCredential.class)); 61 if (in.readInt() == 1) { 62 builder.setFastPairModelId(in.readString()); 63 } 64 if (in.readInt() == 1) { 65 builder.setBluetoothAddress(in.readString()); 66 } 67 if (in.readInt() == 1) { 68 int dataLength = in.readInt(); 69 byte[] data = new byte[dataLength]; 70 in.readByteArray(data); 71 builder.setData(data); 72 } 73 if (in.readInt() == 1) { 74 int saltLength = in.readInt(); 75 byte[] salt = new byte[saltLength]; 76 in.readByteArray(salt); 77 builder.setData(salt); 78 } 79 return builder.build(); 80 } 81 82 @Override 83 public NearbyDeviceParcelable[] newArray(int size) { 84 return new NearbyDeviceParcelable[size]; 85 } 86 }; 87 88 @ScanRequest.ScanType int mScanType; 89 @Nullable private final String mName; 90 @NearbyDevice.Medium private final int mMedium; 91 private final int mTxPower; 92 private final int mRssi; 93 private final int mAction; 94 private final PublicCredential mPublicCredential; 95 @Nullable private final String mBluetoothAddress; 96 @Nullable private final String mFastPairModelId; 97 @Nullable private final byte[] mData; 98 @Nullable private final byte[] mSalt; 99 NearbyDeviceParcelable( @canRequest.ScanType int scanType, @Nullable String name, int medium, int TxPower, int rssi, int action, PublicCredential publicCredential, @Nullable String fastPairModelId, @Nullable String bluetoothAddress, @Nullable byte[] data, @Nullable byte[] salt)100 private NearbyDeviceParcelable( 101 @ScanRequest.ScanType int scanType, 102 @Nullable String name, 103 int medium, 104 int TxPower, 105 int rssi, 106 int action, 107 PublicCredential publicCredential, 108 @Nullable String fastPairModelId, 109 @Nullable String bluetoothAddress, 110 @Nullable byte[] data, 111 @Nullable byte[] salt) { 112 mScanType = scanType; 113 mName = name; 114 mMedium = medium; 115 mTxPower = TxPower; 116 mRssi = rssi; 117 mAction = action; 118 mPublicCredential = publicCredential; 119 mFastPairModelId = fastPairModelId; 120 mBluetoothAddress = bluetoothAddress; 121 mData = data; 122 mSalt = salt; 123 } 124 125 /** No special parcel contents. */ 126 @Override describeContents()127 public int describeContents() { 128 return 0; 129 } 130 131 /** 132 * Flatten this NearbyDeviceParcelable in to a Parcel. 133 * 134 * @param dest The Parcel in which the object should be written. 135 * @param flags Additional flags about how the object should be written. 136 */ 137 @Override writeToParcel(@onNull Parcel dest, int flags)138 public void writeToParcel(@NonNull Parcel dest, int flags) { 139 dest.writeInt(mScanType); 140 dest.writeInt(mName == null ? 0 : 1); 141 if (mName != null) { 142 dest.writeString(mName); 143 } 144 dest.writeInt(mMedium); 145 dest.writeInt(mTxPower); 146 dest.writeInt(mRssi); 147 dest.writeInt(mAction); 148 dest.writeParcelable(mPublicCredential, flags); 149 dest.writeInt(mFastPairModelId == null ? 0 : 1); 150 if (mFastPairModelId != null) { 151 dest.writeString(mFastPairModelId); 152 } 153 dest.writeInt(mBluetoothAddress == null ? 0 : 1); 154 if (mBluetoothAddress != null) { 155 dest.writeString(mBluetoothAddress); 156 } 157 dest.writeInt(mData == null ? 0 : 1); 158 if (mData != null) { 159 dest.writeInt(mData.length); 160 dest.writeByteArray(mData); 161 } 162 dest.writeInt(mSalt == null ? 0 : 1); 163 if (mSalt != null) { 164 dest.writeInt(mSalt.length); 165 dest.writeByteArray(mSalt); 166 } 167 } 168 169 /** Returns a string representation of this ScanRequest. */ 170 @Override toString()171 public String toString() { 172 return "NearbyDeviceParcelable[" 173 + "scanType=" 174 + mScanType 175 + ", name=" 176 + mName 177 + ", medium=" 178 + NearbyDevice.mediumToString(mMedium) 179 + ", txPower=" 180 + mTxPower 181 + ", rssi=" 182 + mRssi 183 + ", action=" 184 + mAction 185 + ", bluetoothAddress=" 186 + mBluetoothAddress 187 + ", fastPairModelId=" 188 + mFastPairModelId 189 + ", data=" 190 + Arrays.toString(mData) 191 + ", salt=" 192 + Arrays.toString(mSalt) 193 + "]"; 194 } 195 196 @Override equals(Object other)197 public boolean equals(Object other) { 198 if (other instanceof NearbyDeviceParcelable) { 199 NearbyDeviceParcelable otherNearbyDeviceParcelable = (NearbyDeviceParcelable) other; 200 return mScanType == otherNearbyDeviceParcelable.mScanType 201 && (Objects.equals(mName, otherNearbyDeviceParcelable.mName)) 202 && (mMedium == otherNearbyDeviceParcelable.mMedium) 203 && (mTxPower == otherNearbyDeviceParcelable.mTxPower) 204 && (mRssi == otherNearbyDeviceParcelable.mRssi) 205 && (mAction == otherNearbyDeviceParcelable.mAction) 206 && (Objects.equals( 207 mPublicCredential, otherNearbyDeviceParcelable.mPublicCredential)) 208 && (Objects.equals( 209 mBluetoothAddress, otherNearbyDeviceParcelable.mBluetoothAddress)) 210 && (Objects.equals( 211 mFastPairModelId, otherNearbyDeviceParcelable.mFastPairModelId)) 212 && (Arrays.equals(mData, otherNearbyDeviceParcelable.mData)) 213 && (Arrays.equals(mSalt, otherNearbyDeviceParcelable.mSalt)); 214 } 215 return false; 216 } 217 218 @Override hashCode()219 public int hashCode() { 220 return Objects.hash( 221 mScanType, 222 mName, 223 mMedium, 224 mRssi, 225 mAction, 226 mPublicCredential.hashCode(), 227 mBluetoothAddress, 228 mFastPairModelId, 229 Arrays.hashCode(mData), 230 Arrays.hashCode(mSalt)); 231 } 232 233 /** 234 * Returns the type of the scan. 235 * 236 * @hide 237 */ 238 @ScanRequest.ScanType getScanType()239 public int getScanType() { 240 return mScanType; 241 } 242 243 /** 244 * Gets the name of the NearbyDeviceParcelable. Returns {@code null} If there is no name. 245 * 246 * Used in Fast Pair. 247 */ 248 @Nullable getName()249 public String getName() { 250 return mName; 251 } 252 253 /** 254 * Gets the {@link android.nearby.NearbyDevice.Medium} of the NearbyDeviceParcelable over which 255 * it is discovered. 256 * 257 * Used in Fast Pair and Nearby Presence. 258 */ 259 @NearbyDevice.Medium getMedium()260 public int getMedium() { 261 return mMedium; 262 } 263 264 /** 265 * Gets the transmission power in dBm. 266 * 267 * Used in Fast Pair. 268 * 269 * @hide 270 */ 271 @IntRange(from = -127, to = 126) getTxPower()272 public int getTxPower() { 273 return mTxPower; 274 } 275 276 /** 277 * Gets the received signal strength in dBm. 278 * 279 * Used in Fast Pair and Nearby Presence. 280 */ 281 @IntRange(from = -127, to = 126) getRssi()282 public int getRssi() { 283 return mRssi; 284 } 285 286 /** 287 * Gets the Action. 288 * 289 * Used in Nearby Presence. 290 * 291 * @hide 292 */ 293 @IntRange(from = -127, to = 126) getAction()294 public int getAction() { 295 return mAction; 296 } 297 298 /** 299 * Gets the public credential. 300 * 301 * Used in Nearby Presence. 302 * 303 * @hide 304 */ 305 @NonNull getPublicCredential()306 public PublicCredential getPublicCredential() { 307 return mPublicCredential; 308 } 309 310 /** 311 * Gets the Fast Pair identifier. Returns {@code null} if there is no Model ID or this is not a 312 * Fast Pair device. 313 * 314 * Used in Fast Pair. 315 */ 316 @Nullable getFastPairModelId()317 public String getFastPairModelId() { 318 return mFastPairModelId; 319 } 320 321 /** 322 * Gets the Bluetooth device hardware address. Returns {@code null} if the device is not 323 * discovered by Bluetooth. 324 * 325 * Used in Fast Pair. 326 */ 327 @Nullable getBluetoothAddress()328 public String getBluetoothAddress() { 329 return mBluetoothAddress; 330 } 331 332 /** 333 * Gets the raw data from the scanning. 334 * Returns {@code null} if there is no extra data or this is not a Fast Pair device. 335 * 336 * Used in Fast Pair. 337 */ 338 @Nullable getData()339 public byte[] getData() { 340 return mData; 341 } 342 343 /** 344 * Gets the salt in the advertisement from the Nearby Presence device. 345 * Returns {@code null} if this is not a Nearby Presence device. 346 * 347 * Used in Nearby Presence. 348 */ 349 @Nullable getSalt()350 public byte[] getSalt() { 351 return mSalt; 352 } 353 354 /** Builder class for {@link NearbyDeviceParcelable}. */ 355 public static final class Builder { 356 @Nullable private String mName; 357 @NearbyDevice.Medium private int mMedium; 358 private int mTxPower; 359 private int mRssi; 360 private int mAction; 361 private PublicCredential mPublicCredential; 362 @ScanRequest.ScanType int mScanType; 363 @Nullable private String mFastPairModelId; 364 @Nullable private String mBluetoothAddress; 365 @Nullable private byte[] mData; 366 @Nullable private byte[] mSalt; 367 368 /** 369 * Sets the scan type of the NearbyDeviceParcelable. 370 * 371 * @hide 372 */ setScanType(@canRequest.ScanType int scanType)373 public Builder setScanType(@ScanRequest.ScanType int scanType) { 374 mScanType = scanType; 375 return this; 376 } 377 378 /** 379 * Sets the name of the scanned device. 380 * 381 * @param name The local name of the scanned device. 382 */ 383 @NonNull setName(@ullable String name)384 public Builder setName(@Nullable String name) { 385 mName = name; 386 return this; 387 } 388 389 /** 390 * Sets the medium over which the device is discovered. 391 * 392 * @param medium The {@link NearbyDevice.Medium} over which the device is discovered. 393 */ 394 @NonNull setMedium(@earbyDevice.Medium int medium)395 public Builder setMedium(@NearbyDevice.Medium int medium) { 396 mMedium = medium; 397 return this; 398 } 399 400 /** 401 * Sets the transmission power of the discovered device. 402 * 403 * @param txPower The transmission power in dBm. 404 * @hide 405 */ 406 @NonNull setTxPower(int txPower)407 public Builder setTxPower(int txPower) { 408 mTxPower = txPower; 409 return this; 410 } 411 412 /** 413 * Sets the RSSI between scanned device and the discovered device. 414 * 415 * @param rssi The received signal strength in dBm. 416 */ 417 @NonNull setRssi(@ntRangefrom = -127, to = 126) int rssi)418 public Builder setRssi(@IntRange(from = -127, to = 126) int rssi) { 419 mRssi = rssi; 420 return this; 421 } 422 423 /** 424 * Sets the action from the discovered device. 425 * 426 * @param action The action of the discovered device. 427 * @hide 428 */ 429 @NonNull setAction(int action)430 public Builder setAction(int action) { 431 mAction = action; 432 return this; 433 } 434 435 /** 436 * Sets the public credential of the discovered device. 437 * 438 * @param publicCredential The public credential. 439 * @hide 440 */ 441 @NonNull setPublicCredential(@onNull PublicCredential publicCredential)442 public Builder setPublicCredential(@NonNull PublicCredential publicCredential) { 443 mPublicCredential = publicCredential; 444 return this; 445 } 446 447 /** 448 * Sets the Fast Pair model Id. 449 * 450 * @param fastPairModelId Fast Pair device identifier. 451 */ 452 @NonNull setFastPairModelId(@ullable String fastPairModelId)453 public Builder setFastPairModelId(@Nullable String fastPairModelId) { 454 mFastPairModelId = fastPairModelId; 455 return this; 456 } 457 458 /** 459 * Sets the bluetooth address. 460 * 461 * @param bluetoothAddress The hardware address of the bluetooth device. 462 */ 463 @NonNull setBluetoothAddress(@ullable String bluetoothAddress)464 public Builder setBluetoothAddress(@Nullable String bluetoothAddress) { 465 mBluetoothAddress = bluetoothAddress; 466 return this; 467 } 468 469 /** 470 * Sets the scanned raw data. 471 * 472 * @param data Data the scan. For example, {@link ScanRecord#getServiceData()} if scanned by 473 * Bluetooth. 474 */ 475 @NonNull setData(@ullable byte[] data)476 public Builder setData(@Nullable byte[] data) { 477 mData = data; 478 return this; 479 } 480 481 /** 482 * Sets the slat in the advertisement from the Nearby Presence device. 483 * 484 * @param salt in the advertisement from the Nearby Presence device. 485 */ 486 @NonNull setSalt(@ullable byte[] salt)487 public Builder setSalt(@Nullable byte[] salt) { 488 mSalt = salt; 489 return this; 490 } 491 492 /** Builds a ScanResult. */ 493 @NonNull build()494 public NearbyDeviceParcelable build() { 495 return new NearbyDeviceParcelable( 496 mScanType, 497 mName, 498 mMedium, 499 mTxPower, 500 mRssi, 501 mAction, 502 mPublicCredential, 503 mFastPairModelId, 504 mBluetoothAddress, 505 mData, 506 mSalt); 507 } 508 } 509 } 510