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.bluetooth.le; 18 19 import static java.util.Objects.requireNonNull; 20 21 import android.annotation.FlaggedApi; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SystemApi; 26 import android.bluetooth.BluetoothAdapter; 27 import android.bluetooth.BluetoothDevice; 28 import android.bluetooth.BluetoothDevice.AddressType; 29 import android.os.Parcel; 30 import android.os.Parcelable; 31 32 import com.android.bluetooth.flags.Flags; 33 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 37 /** 38 * The {@link AdvertisingSetParameters} provide a way to adjust advertising preferences for each 39 * Bluetooth LE advertising set. Use {@link AdvertisingSetParameters.Builder} to create an instance 40 * of this class. 41 */ 42 public final class AdvertisingSetParameters implements Parcelable { 43 44 /** 45 * Advertise on low frequency, around every 1000ms. This is the default and preferred 46 * advertising mode as it consumes the least power. 47 */ 48 public static final int INTERVAL_HIGH = 1600; 49 50 /** 51 * Advertise on medium frequency, around every 250ms. This is balanced between advertising 52 * frequency and power consumption. 53 */ 54 public static final int INTERVAL_MEDIUM = 400; 55 56 /** 57 * Perform high frequency, low latency advertising, around every 100ms. This has the highest 58 * power consumption and should not be used for continuous background advertising. 59 */ 60 public static final int INTERVAL_LOW = 160; 61 62 /** Minimum value for advertising interval. */ 63 public static final int INTERVAL_MIN = 160; 64 65 /** Maximum value for advertising interval. */ 66 public static final int INTERVAL_MAX = 16777215; 67 68 /** 69 * Advertise using the lowest transmission (TX) power level. Low transmission power can be used 70 * to restrict the visibility range of advertising packets. 71 */ 72 public static final int TX_POWER_ULTRA_LOW = -21; 73 74 /** Advertise using low TX power level. */ 75 public static final int TX_POWER_LOW = -15; 76 77 /** Advertise using medium TX power level. */ 78 public static final int TX_POWER_MEDIUM = -7; 79 80 /** 81 * Advertise using high TX power level. This corresponds to largest visibility range of the 82 * advertising packet. 83 */ 84 public static final int TX_POWER_HIGH = 1; 85 86 /** Minimum value for TX power. */ 87 public static final int TX_POWER_MIN = -127; 88 89 /** Maximum value for TX power. */ 90 public static final int TX_POWER_MAX = 1; 91 92 /** @hide */ 93 @IntDef( 94 prefix = "ADDRESS_TYPE_", 95 value = { 96 ADDRESS_TYPE_DEFAULT, 97 ADDRESS_TYPE_PUBLIC, 98 ADDRESS_TYPE_RANDOM, 99 ADDRESS_TYPE_RANDOM_NON_RESOLVABLE, 100 }) 101 @Retention(RetentionPolicy.SOURCE) 102 public @interface AddressTypeStatus {} 103 104 /** 105 * Advertise own address type that corresponds privacy settings of the device. 106 * 107 * @hide 108 */ 109 @SystemApi public static final int ADDRESS_TYPE_DEFAULT = -1; 110 111 /** 112 * Advertise own public address type. 113 * 114 * @hide 115 */ 116 @SystemApi public static final int ADDRESS_TYPE_PUBLIC = 0; 117 118 /** 119 * Generate and advertise own resolvable private address. 120 * 121 * @hide 122 */ 123 @SystemApi public static final int ADDRESS_TYPE_RANDOM = 1; 124 125 /** 126 * Generate and advertise on non-resolvable private address. 127 * 128 * @hide 129 */ 130 @SystemApi public static final int ADDRESS_TYPE_RANDOM_NON_RESOLVABLE = 2; 131 132 private final boolean mIsLegacy; 133 private final boolean mIsAnonymous; 134 private final boolean mIncludeTxPower; 135 private final int mPrimaryPhy; 136 private final int mSecondaryPhy; 137 private final boolean mConnectable; 138 private final boolean mDiscoverable; 139 private final boolean mScannable; 140 private final int mInterval; 141 private final int mTxPowerLevel; 142 private final int mOwnAddressType; 143 private final boolean mIsDirected; 144 private final boolean mIsHighDutyCycle; 145 private final String mPeerAddress; 146 private final @AddressType int mPeerAddressType; 147 AdvertisingSetParameters( boolean connectable, boolean discoverable, boolean scannable, boolean isLegacy, boolean isAnonymous, boolean includeTxPower, int primaryPhy, int secondaryPhy, int interval, int txPowerLevel, @AddressTypeStatus int ownAddressType, boolean isDirected, boolean isHighDutyCycle, String peerAddress, @AddressType int peerAddressType)148 private AdvertisingSetParameters( 149 boolean connectable, 150 boolean discoverable, 151 boolean scannable, 152 boolean isLegacy, 153 boolean isAnonymous, 154 boolean includeTxPower, 155 int primaryPhy, 156 int secondaryPhy, 157 int interval, 158 int txPowerLevel, 159 @AddressTypeStatus int ownAddressType, 160 boolean isDirected, 161 boolean isHighDutyCycle, 162 String peerAddress, 163 @AddressType int peerAddressType) { 164 mConnectable = connectable; 165 mDiscoverable = discoverable; 166 mScannable = scannable; 167 mIsLegacy = isLegacy; 168 mIsAnonymous = isAnonymous; 169 mIncludeTxPower = includeTxPower; 170 mPrimaryPhy = primaryPhy; 171 mSecondaryPhy = secondaryPhy; 172 mInterval = interval; 173 mTxPowerLevel = txPowerLevel; 174 mOwnAddressType = ownAddressType; 175 mIsDirected = isDirected; 176 mIsHighDutyCycle = isHighDutyCycle; 177 mPeerAddress = peerAddress; 178 mPeerAddressType = peerAddressType; 179 } 180 AdvertisingSetParameters(Parcel in)181 private AdvertisingSetParameters(Parcel in) { 182 mConnectable = in.readInt() != 0; 183 mScannable = in.readInt() != 0; 184 mIsLegacy = in.readInt() != 0; 185 mIsAnonymous = in.readInt() != 0; 186 mIncludeTxPower = in.readInt() != 0; 187 mPrimaryPhy = in.readInt(); 188 mSecondaryPhy = in.readInt(); 189 mInterval = in.readInt(); 190 mTxPowerLevel = in.readInt(); 191 mOwnAddressType = in.readInt(); 192 mDiscoverable = in.readInt() != 0; 193 mIsDirected = in.readBoolean(); 194 mIsHighDutyCycle = in.readBoolean(); 195 mPeerAddress = in.readString(); 196 mPeerAddressType = in.readInt(); 197 } 198 199 /** Returns whether the advertisement will be connectable. */ isConnectable()200 public boolean isConnectable() { 201 return mConnectable; 202 } 203 204 /** Returns whether the advertisement will be discoverable. */ isDiscoverable()205 public boolean isDiscoverable() { 206 return mDiscoverable; 207 } 208 209 /** Returns whether the advertisement will be scannable. */ isScannable()210 public boolean isScannable() { 211 return mScannable; 212 } 213 214 /** Returns whether the legacy advertisement will be used. */ isLegacy()215 public boolean isLegacy() { 216 return mIsLegacy; 217 } 218 219 /** Returns whether the advertisement will be anonymous. */ isAnonymous()220 public boolean isAnonymous() { 221 return mIsAnonymous; 222 } 223 224 /** Returns whether the TX Power will be included. */ includeTxPower()225 public boolean includeTxPower() { 226 return mIncludeTxPower; 227 } 228 229 /** Returns the primary advertising phy. */ getPrimaryPhy()230 public int getPrimaryPhy() { 231 return mPrimaryPhy; 232 } 233 234 /** Returns the secondary advertising phy. */ getSecondaryPhy()235 public int getSecondaryPhy() { 236 return mSecondaryPhy; 237 } 238 239 /** Returns the advertising interval. */ getInterval()240 public int getInterval() { 241 return mInterval; 242 } 243 244 /** Returns the TX power level for advertising. */ getTxPowerLevel()245 public int getTxPowerLevel() { 246 return mTxPowerLevel; 247 } 248 249 /** 250 * @return the own address type for advertising 251 * @hide 252 */ 253 @SystemApi getOwnAddressType()254 public @AddressTypeStatus int getOwnAddressType() { 255 return mOwnAddressType; 256 } 257 258 /** 259 * @return Whether the advertisement is directed 260 * @hide This API is not publicly available as it is mainly intended for accessory devices 261 * running Android to broadcast their availability and which can thus leverage system APIs. 262 */ 263 @FlaggedApi(Flags.FLAG_DIRECTED_ADVERTISING_API) 264 @SystemApi isDirected()265 public boolean isDirected() { 266 return mIsDirected; 267 } 268 269 /** 270 * @return Whether the advertisement is high duty cycle or not 271 * @hide This API is not publicly available as it is mainly intended for accessory devices 272 * running Android to broadcast their availability and which can thus leverage system APIs. 273 */ 274 @FlaggedApi(Flags.FLAG_DIRECTED_ADVERTISING_API) 275 @SystemApi isHighDutyCycle()276 public boolean isHighDutyCycle() { 277 return mIsHighDutyCycle; 278 } 279 280 /** 281 * @return Peer address for directed advertising 282 * @hide This API is not publicly available as it is mainly intended for accessory devices 283 * running Android to broadcast their availability and which can thus leverage system APIs. 284 */ 285 @FlaggedApi(Flags.FLAG_DIRECTED_ADVERTISING_API) 286 @SystemApi getPeerAddress()287 public @Nullable String getPeerAddress() { 288 return mPeerAddress; 289 } 290 291 /** 292 * @return Peer address type for directed advertising 293 * @hide This API is not publicly available as it is mainly intended for accessory devices 294 * running Android to broadcast their availability and which can thus leverage system APIs. 295 */ 296 @FlaggedApi(Flags.FLAG_DIRECTED_ADVERTISING_API) 297 @SystemApi getPeerAddressType()298 public @AddressType int getPeerAddressType() { 299 return mPeerAddressType; 300 } 301 302 @Override toString()303 public String toString() { 304 return "AdvertisingSetParameters [connectable=" 305 + mConnectable 306 + ", discoverable=" 307 + mDiscoverable 308 + ", isLegacy=" 309 + mIsLegacy 310 + ", isAnonymous=" 311 + mIsAnonymous 312 + ", includeTxPower=" 313 + mIncludeTxPower 314 + ", primaryPhy=" 315 + mPrimaryPhy 316 + ", secondaryPhy=" 317 + mSecondaryPhy 318 + ", interval=" 319 + mInterval 320 + ", txPowerLevel=" 321 + mTxPowerLevel 322 + ", ownAddressType=" 323 + mOwnAddressType 324 + ", isDirected=" 325 + mIsDirected 326 + ", isHighDutyCycle=" 327 + mIsHighDutyCycle 328 + ", peerAddress=" 329 + mPeerAddress 330 + ", peerAddressType=" 331 + mPeerAddressType 332 + "]"; 333 } 334 335 @Override describeContents()336 public int describeContents() { 337 return 0; 338 } 339 340 @Override writeToParcel(Parcel dest, int flags)341 public void writeToParcel(Parcel dest, int flags) { 342 dest.writeInt(mConnectable ? 1 : 0); 343 dest.writeInt(mScannable ? 1 : 0); 344 dest.writeInt(mIsLegacy ? 1 : 0); 345 dest.writeInt(mIsAnonymous ? 1 : 0); 346 dest.writeInt(mIncludeTxPower ? 1 : 0); 347 dest.writeInt(mPrimaryPhy); 348 dest.writeInt(mSecondaryPhy); 349 dest.writeInt(mInterval); 350 dest.writeInt(mTxPowerLevel); 351 dest.writeInt(mOwnAddressType); 352 dest.writeInt(mDiscoverable ? 1 : 0); 353 dest.writeBoolean(mIsDirected); 354 dest.writeBoolean(mIsHighDutyCycle); 355 android.bluetooth.BluetoothUtils.writeStringToParcel(dest, mPeerAddress); 356 dest.writeInt(mPeerAddressType); 357 } 358 359 public static final @android.annotation.NonNull Parcelable.Creator<AdvertisingSetParameters> 360 CREATOR = 361 new Creator<AdvertisingSetParameters>() { 362 @Override 363 public AdvertisingSetParameters[] newArray(int size) { 364 return new AdvertisingSetParameters[size]; 365 } 366 367 @Override 368 public AdvertisingSetParameters createFromParcel(Parcel in) { 369 return new AdvertisingSetParameters(in); 370 } 371 }; 372 373 /** Builder class for {@link AdvertisingSetParameters}. */ 374 public static final class Builder { 375 private boolean mConnectable = false; 376 private boolean mDiscoverable = true; 377 private boolean mScannable = false; 378 private boolean mIsLegacy = false; 379 private boolean mIsAnonymous = false; 380 private boolean mIncludeTxPower = false; 381 private int mPrimaryPhy = BluetoothDevice.PHY_LE_1M; 382 private int mSecondaryPhy = BluetoothDevice.PHY_LE_1M; 383 private int mInterval = INTERVAL_LOW; 384 private int mTxPowerLevel = TX_POWER_MEDIUM; 385 private int mOwnAddressType = ADDRESS_TYPE_DEFAULT; 386 private boolean mIsDirected = false; 387 private boolean mIsHighDutyCycle = false; 388 private String mPeerAddress = null; 389 private @AddressType int mPeerAddressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC; 390 391 /** 392 * Set whether the advertisement type should be connectable or non-connectable. Legacy 393 * advertisements can be both connectable and scannable. Non-legacy advertisements can be 394 * only scannable or only connectable. 395 * 396 * @param connectable Controls whether the advertisement type will be connectable (true) or 397 * non-connectable (false). 398 */ setConnectable(boolean connectable)399 public Builder setConnectable(boolean connectable) { 400 mConnectable = connectable; 401 return this; 402 } 403 404 /** 405 * Set whether the advertisement type should be discoverable or non-discoverable. By 406 * default, advertisements will be discoverable. Devices connecting to non-discoverable 407 * advertisements cannot initiate bonding. 408 * 409 * @param discoverable Controls whether the advertisement type will be discoverable ({@code 410 * true}) or non-discoverable ({@code false}). 411 */ setDiscoverable(boolean discoverable)412 public @NonNull Builder setDiscoverable(boolean discoverable) { 413 mDiscoverable = discoverable; 414 return this; 415 } 416 417 /** 418 * Set whether the advertisement type should be scannable. Legacy advertisements can be both 419 * connectable and scannable. Non-legacy advertisements can be only scannable or only 420 * connectable. 421 * 422 * @param scannable Controls whether the advertisement type will be scannable (true) or 423 * non-scannable (false). 424 */ setScannable(boolean scannable)425 public Builder setScannable(boolean scannable) { 426 mScannable = scannable; 427 return this; 428 } 429 430 /** 431 * When set to true, advertising set will advertise 4.x Spec compliant advertisements. 432 * 433 * @param isLegacy whether legacy advertising mode should be used. 434 */ setLegacyMode(boolean isLegacy)435 public Builder setLegacyMode(boolean isLegacy) { 436 mIsLegacy = isLegacy; 437 return this; 438 } 439 440 /** 441 * Set whether advertiser address should be omitted from all packets. If this mode is used, 442 * periodic advertising can't be enabled for this set. 443 * 444 * <p>This is used only if legacy mode is not used. 445 * 446 * @param isAnonymous whether anonymous advertising should be used. 447 */ setAnonymous(boolean isAnonymous)448 public Builder setAnonymous(boolean isAnonymous) { 449 mIsAnonymous = isAnonymous; 450 return this; 451 } 452 453 /** 454 * Set whether TX power should be included in the extended header. 455 * 456 * <p>This is used only if legacy mode is not used. 457 * 458 * @param includeTxPower whether TX power should be included in extended header 459 */ setIncludeTxPower(boolean includeTxPower)460 public Builder setIncludeTxPower(boolean includeTxPower) { 461 mIncludeTxPower = includeTxPower; 462 return this; 463 } 464 465 /** 466 * Set the primary physical channel used for this advertising set. 467 * 468 * <p>This is used only if legacy mode is not used. 469 * 470 * <p>Use {@link BluetoothAdapter#isLeCodedPhySupported} to determine if LE Coded PHY is 471 * supported on this device. 472 * 473 * @param primaryPhy Primary advertising physical channel, can only be {@link 474 * BluetoothDevice#PHY_LE_1M} or {@link BluetoothDevice#PHY_LE_CODED}. 475 * @throws IllegalArgumentException If the primaryPhy is invalid. 476 */ setPrimaryPhy(int primaryPhy)477 public Builder setPrimaryPhy(int primaryPhy) { 478 if (primaryPhy != BluetoothDevice.PHY_LE_1M 479 && primaryPhy != BluetoothDevice.PHY_LE_CODED) { 480 throw new IllegalArgumentException("bad primaryPhy " + primaryPhy); 481 } 482 mPrimaryPhy = primaryPhy; 483 return this; 484 } 485 486 /** 487 * Set the secondary physical channel used for this advertising set. 488 * 489 * <p>This is used only if legacy mode is not used. 490 * 491 * <p>Use {@link BluetoothAdapter#isLeCodedPhySupported} and {@link 492 * BluetoothAdapter#isLe2MPhySupported} to determine if LE Coded PHY or 2M PHY is supported 493 * on this device. 494 * 495 * @param secondaryPhy Secondary advertising physical channel, can only be one of {@link 496 * BluetoothDevice#PHY_LE_1M}, {@link BluetoothDevice#PHY_LE_2M} or {@link 497 * BluetoothDevice#PHY_LE_CODED}. 498 * @throws IllegalArgumentException If the secondaryPhy is invalid. 499 */ setSecondaryPhy(int secondaryPhy)500 public Builder setSecondaryPhy(int secondaryPhy) { 501 if (secondaryPhy != BluetoothDevice.PHY_LE_1M 502 && secondaryPhy != BluetoothDevice.PHY_LE_2M 503 && secondaryPhy != BluetoothDevice.PHY_LE_CODED) { 504 throw new IllegalArgumentException("bad secondaryPhy " + secondaryPhy); 505 } 506 mSecondaryPhy = secondaryPhy; 507 return this; 508 } 509 510 /** 511 * Set advertising interval. 512 * 513 * @param interval Bluetooth LE Advertising interval, in 0.625ms unit. Valid range is from 514 * 160 (100ms) to 16777215 (10,485.759375 s). Recommended values are: {@link 515 * AdvertisingSetParameters#INTERVAL_LOW}, {@link 516 * AdvertisingSetParameters#INTERVAL_MEDIUM}, or {@link 517 * AdvertisingSetParameters#INTERVAL_HIGH}. 518 * @throws IllegalArgumentException If the interval is invalid. 519 */ setInterval(int interval)520 public Builder setInterval(int interval) { 521 if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { 522 throw new IllegalArgumentException("unknown interval " + interval); 523 } 524 mInterval = interval; 525 return this; 526 } 527 528 /** 529 * Set the transmission power level for the advertising. 530 * 531 * @param txPowerLevel Transmission power of Bluetooth LE Advertising, in dBm. The valid 532 * range is [-127, 1] Recommended values are: {@link 533 * AdvertisingSetParameters#TX_POWER_ULTRA_LOW}, {@link 534 * AdvertisingSetParameters#TX_POWER_LOW}, {@link 535 * AdvertisingSetParameters#TX_POWER_MEDIUM}, or {@link 536 * AdvertisingSetParameters#TX_POWER_HIGH}. 537 * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid. 538 */ setTxPowerLevel(int txPowerLevel)539 public Builder setTxPowerLevel(int txPowerLevel) { 540 if (txPowerLevel < TX_POWER_MIN || txPowerLevel > TX_POWER_MAX) { 541 throw new IllegalArgumentException("unknown txPowerLevel " + txPowerLevel); 542 } 543 mTxPowerLevel = txPowerLevel; 544 return this; 545 } 546 547 /** 548 * Set own address type for advertising to control public or privacy mode. If used to set 549 * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT}, 550 * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the time of 551 * starting advertising. 552 * 553 * @throws IllegalArgumentException If the {@code ownAddressType} is invalid 554 * @hide 555 */ 556 @SystemApi setOwnAddressType(@ddressTypeStatus int ownAddressType)557 public @NonNull Builder setOwnAddressType(@AddressTypeStatus int ownAddressType) { 558 if (ownAddressType < AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT 559 || ownAddressType 560 > AdvertisingSetParameters.ADDRESS_TYPE_RANDOM_NON_RESOLVABLE) { 561 throw new IllegalArgumentException("unknown address type " + ownAddressType); 562 } 563 mOwnAddressType = ownAddressType; 564 return this; 565 } 566 567 /** 568 * Set whether the advertising is a directed advertising. 569 * 570 * @param isDirected Controls whether the advertising is directed or not 571 * @hide This API is not publicly available as it is mainly intended for accessory devices 572 * running Android to broadcast their availability and which can thus leverage system 573 * APIs. 574 */ 575 @FlaggedApi(Flags.FLAG_DIRECTED_ADVERTISING_API) 576 @SystemApi setDirected(boolean isDirected)577 public @NonNull Builder setDirected(boolean isDirected) { 578 mIsDirected = isDirected; 579 return this; 580 } 581 582 /** 583 * Set whether the advertising is high duty cycle or not. 584 * 585 * @param isHighDutyCycle Controls whether the advertising high duty cycle or not 586 * @hide This API is not publicly available as it is mainly intended for accessory devices 587 * running Android to broadcast their availability and which can thus leverage system 588 * APIs. 589 */ 590 @FlaggedApi(Flags.FLAG_DIRECTED_ADVERTISING_API) 591 @SystemApi setHighDutyCycle(boolean isHighDutyCycle)592 public @NonNull Builder setHighDutyCycle(boolean isHighDutyCycle) { 593 mIsHighDutyCycle = isHighDutyCycle; 594 return this; 595 } 596 597 /** 598 * Set peer address for directed advertising. 599 * 600 * @param peerAddress peer address for the directed advertising 601 * @throws IllegalArgumentException peer address is invalid 602 * @hide This API is not publicly available as it is mainly intended for accessory devices 603 * running Android to broadcast their availability and which can thus leverage system 604 * APIs. 605 */ 606 @FlaggedApi(Flags.FLAG_DIRECTED_ADVERTISING_API) 607 @SystemApi setPeerAddress(@onNull String peerAddress)608 public @NonNull Builder setPeerAddress(@NonNull String peerAddress) { 609 requireNonNull(peerAddress); 610 if (!BluetoothAdapter.checkBluetoothAddress(peerAddress)) { 611 throw new IllegalArgumentException( 612 peerAddress + " is not a valid Bluetooth address"); 613 } 614 mPeerAddress = peerAddress; 615 return this; 616 } 617 618 /** 619 * Set peer address type for directed advertising. 620 * 621 * @param peerAddressType peer address type for the directed advertising 622 * @throws IllegalArgumentException if {@code peerAddressType} is invalid 623 * @hide This API is not publicly available as it is mainly intended for accessory devices 624 * running Android to broadcast their availability and which can thus leverage system 625 * APIs. 626 */ 627 @FlaggedApi(Flags.FLAG_DIRECTED_ADVERTISING_API) 628 @SystemApi setPeerAddressType(@ddressType int peerAddressType)629 public @NonNull Builder setPeerAddressType(@AddressType int peerAddressType) { 630 switch (peerAddressType) { 631 case BluetoothDevice.ADDRESS_TYPE_PUBLIC: 632 case BluetoothDevice.ADDRESS_TYPE_RANDOM: 633 mPeerAddressType = peerAddressType; 634 break; 635 case BluetoothDevice.ADDRESS_TYPE_UNKNOWN: 636 case BluetoothDevice.ADDRESS_TYPE_ANONYMOUS: 637 throw new IllegalArgumentException( 638 "unsupported peer address type " + peerAddressType); 639 default: 640 throw new IllegalArgumentException( 641 "unknown peer address type " + peerAddressType); 642 } 643 return this; 644 } 645 646 /** 647 * Build the {@link AdvertisingSetParameters} object. 648 * 649 * @throws IllegalStateException if invalid combination of parameters is used. 650 */ build()651 public AdvertisingSetParameters build() { 652 if (mIsLegacy) { 653 if (mIsAnonymous) { 654 throw new IllegalArgumentException("Legacy advertising can't be anonymous"); 655 } 656 657 if (mIsDirected && !mConnectable) { 658 throw new IllegalStateException( 659 "Legacy directed advertising must be connectable"); 660 } 661 662 if (mIsDirected && mScannable) { 663 throw new IllegalStateException( 664 "Legacy directed advertising can't be scannable"); 665 } 666 667 if (!mIsDirected && mIsHighDutyCycle) { 668 throw new IllegalStateException( 669 "Non-directed legacy advertising can't be high duty cycle"); 670 } 671 672 if (!mIsDirected && mConnectable && !mScannable) { 673 throw new IllegalStateException( 674 "Non-directed legacy advertising can't be connectable and" 675 + " non-scannable"); 676 } 677 678 if (mIncludeTxPower) { 679 throw new IllegalStateException( 680 "Legacy advertising can't include TX power level in header"); 681 } 682 } else { 683 if (mConnectable && mScannable) { 684 throw new IllegalStateException( 685 "Advertising can't be both connectable and scannable"); 686 } 687 688 if (mIsAnonymous && mConnectable) { 689 throw new IllegalStateException( 690 "Advertising can't be both connectable and anonymous"); 691 } 692 693 if (mIsHighDutyCycle) { 694 throw new IllegalStateException( 695 "Non-legacy advertising can't be high duty cycle"); 696 } 697 } 698 699 if (mIsDirected && mPeerAddress == null) { 700 throw new IllegalStateException( 701 "Peer address should not be null for directed advertising"); 702 } 703 704 return new AdvertisingSetParameters( 705 mConnectable, 706 mDiscoverable, 707 mScannable, 708 mIsLegacy, 709 mIsAnonymous, 710 mIncludeTxPower, 711 mPrimaryPhy, 712 mSecondaryPhy, 713 mInterval, 714 mTxPowerLevel, 715 mOwnAddressType, 716 mIsDirected, 717 mIsHighDutyCycle, 718 mPeerAddress, 719 mPeerAddressType); 720 } 721 } 722 } 723