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