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 android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.BluetoothDevice; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 24 /** 25 * The {@link AdvertisingSetParameters} provide a way to adjust advertising 26 * preferences for each 27 * Bluetooth LE advertising set. Use {@link AdvertisingSetParameters.Builder} to 28 * create an 29 * instance of this class. 30 */ 31 public final class AdvertisingSetParameters implements Parcelable { 32 33 /** 34 * Advertise on low frequency, around every 1000ms. This is the default and 35 * preferred advertising mode as it consumes the least power. 36 */ 37 public static final int INTERVAL_HIGH = 1600; 38 39 /** 40 * Advertise on medium frequency, around every 250ms. This is balanced 41 * between advertising frequency and power consumption. 42 */ 43 public static final int INTERVAL_MEDIUM = 400; 44 45 /** 46 * Perform high frequency, low latency advertising, around every 100ms. This 47 * has the highest power consumption and should not be used for continuous 48 * background advertising. 49 */ 50 public static final int INTERVAL_LOW = 160; 51 52 /** 53 * Minimum value for advertising interval. 54 */ 55 public static final int INTERVAL_MIN = 160; 56 57 /** 58 * Maximum value for advertising interval. 59 */ 60 public static final int INTERVAL_MAX = 16777215; 61 62 /** 63 * Advertise using the lowest transmission (TX) power level. Low transmission 64 * power can be used to restrict the visibility range of advertising packets. 65 */ 66 public static final int TX_POWER_ULTRA_LOW = -21; 67 68 /** 69 * Advertise using low TX power level. 70 */ 71 public static final int TX_POWER_LOW = -15; 72 73 /** 74 * Advertise using medium TX power level. 75 */ 76 public static final int TX_POWER_MEDIUM = -7; 77 78 /** 79 * Advertise using high TX power level. This corresponds to largest visibility 80 * range of the advertising packet. 81 */ 82 public static final int TX_POWER_HIGH = 1; 83 84 /** 85 * Minimum value for TX power. 86 */ 87 public static final int TX_POWER_MIN = -127; 88 89 /** 90 * Maximum value for TX power. 91 */ 92 public static final int TX_POWER_MAX = 1; 93 94 /** 95 * The maximum limited advertisement duration as specified by the Bluetooth 96 * SIG 97 */ 98 private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000; 99 100 private final boolean mIsLegacy; 101 private final boolean mIsAnonymous; 102 private final boolean mIncludeTxPower; 103 private final int mPrimaryPhy; 104 private final int mSecondaryPhy; 105 private final boolean mConnectable; 106 private final boolean mScannable; 107 private final int mInterval; 108 private final int mTxPowerLevel; 109 AdvertisingSetParameters(boolean connectable, boolean scannable, boolean isLegacy, boolean isAnonymous, boolean includeTxPower, int primaryPhy, int secondaryPhy, int interval, int txPowerLevel)110 private AdvertisingSetParameters(boolean connectable, boolean scannable, boolean isLegacy, 111 boolean isAnonymous, boolean includeTxPower, 112 int primaryPhy, int secondaryPhy, 113 int interval, int txPowerLevel) { 114 mConnectable = connectable; 115 mScannable = scannable; 116 mIsLegacy = isLegacy; 117 mIsAnonymous = isAnonymous; 118 mIncludeTxPower = includeTxPower; 119 mPrimaryPhy = primaryPhy; 120 mSecondaryPhy = secondaryPhy; 121 mInterval = interval; 122 mTxPowerLevel = txPowerLevel; 123 } 124 AdvertisingSetParameters(Parcel in)125 private AdvertisingSetParameters(Parcel in) { 126 mConnectable = in.readInt() != 0; 127 mScannable = in.readInt() != 0; 128 mIsLegacy = in.readInt() != 0; 129 mIsAnonymous = in.readInt() != 0; 130 mIncludeTxPower = in.readInt() != 0; 131 mPrimaryPhy = in.readInt(); 132 mSecondaryPhy = in.readInt(); 133 mInterval = in.readInt(); 134 mTxPowerLevel = in.readInt(); 135 } 136 137 /** 138 * Returns whether the advertisement will be connectable. 139 */ isConnectable()140 public boolean isConnectable() { 141 return mConnectable; 142 } 143 144 /** 145 * Returns whether the advertisement will be scannable. 146 */ isScannable()147 public boolean isScannable() { 148 return mScannable; 149 } 150 151 /** 152 * Returns whether the legacy advertisement will be used. 153 */ isLegacy()154 public boolean isLegacy() { 155 return mIsLegacy; 156 } 157 158 /** 159 * Returns whether the advertisement will be anonymous. 160 */ isAnonymous()161 public boolean isAnonymous() { 162 return mIsAnonymous; 163 } 164 165 /** 166 * Returns whether the TX Power will be included. 167 */ includeTxPower()168 public boolean includeTxPower() { 169 return mIncludeTxPower; 170 } 171 172 /** 173 * Returns the primary advertising phy. 174 */ getPrimaryPhy()175 public int getPrimaryPhy() { 176 return mPrimaryPhy; 177 } 178 179 /** 180 * Returns the secondary advertising phy. 181 */ getSecondaryPhy()182 public int getSecondaryPhy() { 183 return mSecondaryPhy; 184 } 185 186 /** 187 * Returns the advertising interval. 188 */ getInterval()189 public int getInterval() { 190 return mInterval; 191 } 192 193 /** 194 * Returns the TX power level for advertising. 195 */ getTxPowerLevel()196 public int getTxPowerLevel() { 197 return mTxPowerLevel; 198 } 199 200 @Override toString()201 public String toString() { 202 return "AdvertisingSetParameters [connectable=" + mConnectable 203 + ", isLegacy=" + mIsLegacy 204 + ", isAnonymous=" + mIsAnonymous 205 + ", includeTxPower=" + mIncludeTxPower 206 + ", primaryPhy=" + mPrimaryPhy 207 + ", secondaryPhy=" + mSecondaryPhy 208 + ", interval=" + mInterval 209 + ", txPowerLevel=" + mTxPowerLevel + "]"; 210 } 211 212 @Override describeContents()213 public int describeContents() { 214 return 0; 215 } 216 217 @Override writeToParcel(Parcel dest, int flags)218 public void writeToParcel(Parcel dest, int flags) { 219 dest.writeInt(mConnectable ? 1 : 0); 220 dest.writeInt(mScannable ? 1 : 0); 221 dest.writeInt(mIsLegacy ? 1 : 0); 222 dest.writeInt(mIsAnonymous ? 1 : 0); 223 dest.writeInt(mIncludeTxPower ? 1 : 0); 224 dest.writeInt(mPrimaryPhy); 225 dest.writeInt(mSecondaryPhy); 226 dest.writeInt(mInterval); 227 dest.writeInt(mTxPowerLevel); 228 } 229 230 public static final @android.annotation.NonNull Parcelable.Creator<AdvertisingSetParameters> CREATOR = 231 new Creator<AdvertisingSetParameters>() { 232 @Override 233 public AdvertisingSetParameters[] newArray(int size) { 234 return new AdvertisingSetParameters[size]; 235 } 236 237 @Override 238 public AdvertisingSetParameters createFromParcel(Parcel in) { 239 return new AdvertisingSetParameters(in); 240 } 241 }; 242 243 /** 244 * Builder class for {@link AdvertisingSetParameters}. 245 */ 246 public static final class Builder { 247 private boolean mConnectable = false; 248 private boolean mScannable = false; 249 private boolean mIsLegacy = false; 250 private boolean mIsAnonymous = false; 251 private boolean mIncludeTxPower = false; 252 private int mPrimaryPhy = BluetoothDevice.PHY_LE_1M; 253 private int mSecondaryPhy = BluetoothDevice.PHY_LE_1M; 254 private int mInterval = INTERVAL_LOW; 255 private int mTxPowerLevel = TX_POWER_MEDIUM; 256 257 /** 258 * Set whether the advertisement type should be connectable or 259 * non-connectable. 260 * Legacy advertisements can be both connectable and scannable. Non-legacy 261 * advertisements can be only scannable or only connectable. 262 * 263 * @param connectable Controls whether the advertisement type will be connectable (true) or 264 * non-connectable (false). 265 */ setConnectable(boolean connectable)266 public Builder setConnectable(boolean connectable) { 267 mConnectable = connectable; 268 return this; 269 } 270 271 /** 272 * Set whether the advertisement type should be scannable. 273 * Legacy advertisements can be both connectable and scannable. Non-legacy 274 * advertisements can be only scannable or only connectable. 275 * 276 * @param scannable Controls whether the advertisement type will be scannable (true) or 277 * non-scannable (false). 278 */ setScannable(boolean scannable)279 public Builder setScannable(boolean scannable) { 280 mScannable = scannable; 281 return this; 282 } 283 284 /** 285 * When set to true, advertising set will advertise 4.x Spec compliant 286 * advertisements. 287 * 288 * @param isLegacy whether legacy advertising mode should be used. 289 */ setLegacyMode(boolean isLegacy)290 public Builder setLegacyMode(boolean isLegacy) { 291 mIsLegacy = isLegacy; 292 return this; 293 } 294 295 /** 296 * Set whether advertiser address should be ommited from all packets. If this 297 * mode is used, periodic advertising can't be enabled for this set. 298 * 299 * This is used only if legacy mode is not used. 300 * 301 * @param isAnonymous whether anonymous advertising should be used. 302 */ setAnonymous(boolean isAnonymous)303 public Builder setAnonymous(boolean isAnonymous) { 304 mIsAnonymous = isAnonymous; 305 return this; 306 } 307 308 /** 309 * Set whether TX power should be included in the extended header. 310 * 311 * This is used only if legacy mode is not used. 312 * 313 * @param includeTxPower whether TX power should be included in extended header 314 */ setIncludeTxPower(boolean includeTxPower)315 public Builder setIncludeTxPower(boolean includeTxPower) { 316 mIncludeTxPower = includeTxPower; 317 return this; 318 } 319 320 /** 321 * Set the primary physical channel used for this advertising set. 322 * 323 * This is used only if legacy mode is not used. 324 * 325 * Use {@link BluetoothAdapter#isLeCodedPhySupported} to determine if LE Coded PHY is 326 * supported on this device. 327 * 328 * @param primaryPhy Primary advertising physical channel, can only be {@link 329 * BluetoothDevice#PHY_LE_1M} or {@link BluetoothDevice#PHY_LE_CODED}. 330 * @throws IllegalArgumentException If the primaryPhy is invalid. 331 */ setPrimaryPhy(int primaryPhy)332 public Builder setPrimaryPhy(int primaryPhy) { 333 if (primaryPhy != BluetoothDevice.PHY_LE_1M 334 && primaryPhy != BluetoothDevice.PHY_LE_CODED) { 335 throw new IllegalArgumentException("bad primaryPhy " + primaryPhy); 336 } 337 mPrimaryPhy = primaryPhy; 338 return this; 339 } 340 341 /** 342 * Set the secondary physical channel used for this advertising set. 343 * 344 * This is used only if legacy mode is not used. 345 * 346 * Use {@link BluetoothAdapter#isLeCodedPhySupported} and 347 * {@link BluetoothAdapter#isLe2MPhySupported} to determine if LE Coded PHY or 2M PHY is 348 * supported on this device. 349 * 350 * @param secondaryPhy Secondary advertising physical channel, can only be one of {@link 351 * BluetoothDevice#PHY_LE_1M}, {@link BluetoothDevice#PHY_LE_2M} or {@link 352 * BluetoothDevice#PHY_LE_CODED}. 353 * @throws IllegalArgumentException If the secondaryPhy is invalid. 354 */ setSecondaryPhy(int secondaryPhy)355 public Builder setSecondaryPhy(int secondaryPhy) { 356 if (secondaryPhy != BluetoothDevice.PHY_LE_1M 357 && secondaryPhy != BluetoothDevice.PHY_LE_2M 358 && secondaryPhy != BluetoothDevice.PHY_LE_CODED) { 359 throw new IllegalArgumentException("bad secondaryPhy " + secondaryPhy); 360 } 361 mSecondaryPhy = secondaryPhy; 362 return this; 363 } 364 365 /** 366 * Set advertising interval. 367 * 368 * @param interval Bluetooth LE Advertising interval, in 0.625ms unit. Valid range is from 369 * 160 (100ms) to 16777215 (10,485.759375 s). Recommended values are: {@link 370 * AdvertisingSetParameters#INTERVAL_LOW}, {@link AdvertisingSetParameters#INTERVAL_MEDIUM}, 371 * or {@link AdvertisingSetParameters#INTERVAL_HIGH}. 372 * @throws IllegalArgumentException If the interval is invalid. 373 */ setInterval(int interval)374 public Builder setInterval(int interval) { 375 if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { 376 throw new IllegalArgumentException("unknown interval " + interval); 377 } 378 mInterval = interval; 379 return this; 380 } 381 382 /** 383 * Set the transmission power level for the advertising. 384 * 385 * @param txPowerLevel Transmission power of Bluetooth LE Advertising, in dBm. The valid 386 * range is [-127, 1] Recommended values are: 387 * {@link AdvertisingSetParameters#TX_POWER_ULTRA_LOW}, 388 * {@link AdvertisingSetParameters#TX_POWER_LOW}, 389 * {@link AdvertisingSetParameters#TX_POWER_MEDIUM}, 390 * or {@link AdvertisingSetParameters#TX_POWER_HIGH}. 391 * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid. 392 */ setTxPowerLevel(int txPowerLevel)393 public Builder setTxPowerLevel(int txPowerLevel) { 394 if (txPowerLevel < TX_POWER_MIN || txPowerLevel > TX_POWER_MAX) { 395 throw new IllegalArgumentException("unknown txPowerLevel " + txPowerLevel); 396 } 397 mTxPowerLevel = txPowerLevel; 398 return this; 399 } 400 401 /** 402 * Build the {@link AdvertisingSetParameters} object. 403 * 404 * @throws IllegalStateException if invalid combination of parameters is used. 405 */ build()406 public AdvertisingSetParameters build() { 407 if (mIsLegacy) { 408 if (mIsAnonymous) { 409 throw new IllegalArgumentException("Legacy advertising can't be anonymous"); 410 } 411 412 if (mConnectable && !mScannable) { 413 throw new IllegalStateException( 414 "Legacy advertisement can't be connectable and non-scannable"); 415 } 416 417 if (mIncludeTxPower) { 418 throw new IllegalStateException( 419 "Legacy advertising can't include TX power level in header"); 420 } 421 } else { 422 if (mConnectable && mScannable) { 423 throw new IllegalStateException( 424 "Advertising can't be both connectable and scannable"); 425 } 426 427 if (mIsAnonymous && mConnectable) { 428 throw new IllegalStateException( 429 "Advertising can't be both connectable and anonymous"); 430 } 431 } 432 433 return new AdvertisingSetParameters(mConnectable, mScannable, mIsLegacy, mIsAnonymous, 434 mIncludeTxPower, mPrimaryPhy, mSecondaryPhy, mInterval, mTxPowerLevel); 435 } 436 } 437 } 438