• 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         ADDRESS_TYPE_RANDOM_NON_RESOLVABLE,
112     })
113     @Retention(RetentionPolicy.SOURCE)
114     public @interface AddressTypeStatus {}
115 
116     /**
117      * Advertise own address type that corresponds privacy settings of the device.
118      *
119      * @hide
120      */
121     @SystemApi
122     public static final int ADDRESS_TYPE_DEFAULT = -1;
123 
124     /**
125      * Advertise own public address type.
126      *
127      * @hide
128      */
129     @SystemApi
130     public static final int ADDRESS_TYPE_PUBLIC = 0;
131 
132     /**
133      * Generate and adverise own resolvable private address.
134      *
135      * @hide
136      */
137     @SystemApi
138     public static final int ADDRESS_TYPE_RANDOM = 1;
139 
140     /**
141      * Generate and advertise on non-resolvable private address.
142      *
143      * @hide
144      */
145     @SystemApi
146     public static final int ADDRESS_TYPE_RANDOM_NON_RESOLVABLE = 2;
147 
148     private final boolean mIsLegacy;
149     private final boolean mIsAnonymous;
150     private final boolean mIncludeTxPower;
151     private final int mPrimaryPhy;
152     private final int mSecondaryPhy;
153     private final boolean mConnectable;
154     private final boolean mDiscoverable;
155     private final boolean mScannable;
156     private final int mInterval;
157     private final int mTxPowerLevel;
158     private final int mOwnAddressType;
159 
AdvertisingSetParameters( boolean connectable, boolean discoverable, boolean scannable, boolean isLegacy, boolean isAnonymous, boolean includeTxPower, int primaryPhy, int secondaryPhy, int interval, int txPowerLevel, @AddressTypeStatus int ownAddressType)160     private AdvertisingSetParameters(
161             boolean connectable,
162             boolean discoverable,
163             boolean scannable,
164             boolean isLegacy,
165             boolean isAnonymous,
166             boolean includeTxPower,
167             int primaryPhy,
168             int secondaryPhy,
169             int interval,
170             int txPowerLevel,
171             @AddressTypeStatus int ownAddressType) {
172         mConnectable = connectable;
173         mDiscoverable = discoverable;
174         mScannable = scannable;
175         mIsLegacy = isLegacy;
176         mIsAnonymous = isAnonymous;
177         mIncludeTxPower = includeTxPower;
178         mPrimaryPhy = primaryPhy;
179         mSecondaryPhy = secondaryPhy;
180         mInterval = interval;
181         mTxPowerLevel = txPowerLevel;
182         mOwnAddressType = ownAddressType;
183     }
184 
AdvertisingSetParameters(Parcel in)185     private AdvertisingSetParameters(Parcel in) {
186         mConnectable = in.readInt() != 0;
187         mScannable = in.readInt() != 0;
188         mIsLegacy = in.readInt() != 0;
189         mIsAnonymous = in.readInt() != 0;
190         mIncludeTxPower = in.readInt() != 0;
191         mPrimaryPhy = in.readInt();
192         mSecondaryPhy = in.readInt();
193         mInterval = in.readInt();
194         mTxPowerLevel = in.readInt();
195         mOwnAddressType = in.readInt();
196         mDiscoverable = in.readInt() != 0;
197     }
198 
199     /**
200      * Returns whether the advertisement will be connectable.
201      */
isConnectable()202     public boolean isConnectable() {
203         return mConnectable;
204     }
205 
206     /**
207      * Returns whether the advertisement will be discoverable.
208      */
isDiscoverable()209     public boolean isDiscoverable() {
210         return mDiscoverable;
211     }
212 
213     /**
214      * Returns whether the advertisement will be scannable.
215      */
isScannable()216     public boolean isScannable() {
217         return mScannable;
218     }
219 
220     /**
221      * Returns whether the legacy advertisement will be used.
222      */
isLegacy()223     public boolean isLegacy() {
224         return mIsLegacy;
225     }
226 
227     /**
228      * Returns whether the advertisement will be anonymous.
229      */
isAnonymous()230     public boolean isAnonymous() {
231         return mIsAnonymous;
232     }
233 
234     /**
235      * Returns whether the TX Power will be included.
236      */
includeTxPower()237     public boolean includeTxPower() {
238         return mIncludeTxPower;
239     }
240 
241     /**
242      * Returns the primary advertising phy.
243      */
getPrimaryPhy()244     public int getPrimaryPhy() {
245         return mPrimaryPhy;
246     }
247 
248     /**
249      * Returns the secondary advertising phy.
250      */
getSecondaryPhy()251     public int getSecondaryPhy() {
252         return mSecondaryPhy;
253     }
254 
255     /**
256      * Returns the advertising interval.
257      */
getInterval()258     public int getInterval() {
259         return mInterval;
260     }
261 
262     /**
263      * Returns the TX power level for advertising.
264      */
getTxPowerLevel()265     public int getTxPowerLevel() {
266         return mTxPowerLevel;
267     }
268 
269     /**
270      * @return the own address type for advertising
271      *
272      * @hide
273      */
274     @SystemApi
getOwnAddressType()275     public @AddressTypeStatus int getOwnAddressType() {
276         return mOwnAddressType;
277     }
278 
279     @Override
toString()280     public String toString() {
281         return "AdvertisingSetParameters [connectable=" + mConnectable
282                 + ", discoverable=" + mDiscoverable
283                 + ", isLegacy=" + mIsLegacy
284                 + ", isAnonymous=" + mIsAnonymous
285                 + ", includeTxPower=" + mIncludeTxPower
286                 + ", primaryPhy=" + mPrimaryPhy
287                 + ", secondaryPhy=" + mSecondaryPhy
288                 + ", interval=" + mInterval
289                 + ", txPowerLevel=" + mTxPowerLevel
290                 + ", ownAddressType=" + mOwnAddressType + "]";
291     }
292 
293     @Override
describeContents()294     public int describeContents() {
295         return 0;
296     }
297 
298     @Override
writeToParcel(Parcel dest, int flags)299     public void writeToParcel(Parcel dest, int flags) {
300         dest.writeInt(mConnectable ? 1 : 0);
301         dest.writeInt(mScannable ? 1 : 0);
302         dest.writeInt(mIsLegacy ? 1 : 0);
303         dest.writeInt(mIsAnonymous ? 1 : 0);
304         dest.writeInt(mIncludeTxPower ? 1 : 0);
305         dest.writeInt(mPrimaryPhy);
306         dest.writeInt(mSecondaryPhy);
307         dest.writeInt(mInterval);
308         dest.writeInt(mTxPowerLevel);
309         dest.writeInt(mOwnAddressType);
310         dest.writeInt(mDiscoverable ? 1 : 0);
311     }
312 
313     public static final @android.annotation.NonNull Parcelable.Creator<AdvertisingSetParameters> CREATOR =
314             new Creator<AdvertisingSetParameters>() {
315                 @Override
316                 public AdvertisingSetParameters[] newArray(int size) {
317                     return new AdvertisingSetParameters[size];
318                 }
319 
320                 @Override
321                 public AdvertisingSetParameters createFromParcel(Parcel in) {
322                     return new AdvertisingSetParameters(in);
323                 }
324             };
325 
326     /**
327      * Builder class for {@link AdvertisingSetParameters}.
328      */
329     public static final class Builder {
330         private boolean mConnectable = false;
331         private boolean mDiscoverable = true;
332         private boolean mScannable = false;
333         private boolean mIsLegacy = false;
334         private boolean mIsAnonymous = false;
335         private boolean mIncludeTxPower = false;
336         private int mPrimaryPhy = BluetoothDevice.PHY_LE_1M;
337         private int mSecondaryPhy = BluetoothDevice.PHY_LE_1M;
338         private int mInterval = INTERVAL_LOW;
339         private int mTxPowerLevel = TX_POWER_MEDIUM;
340         private int mOwnAddressType = ADDRESS_TYPE_DEFAULT;
341 
342         /**
343          * Set whether the advertisement type should be connectable or
344          * non-connectable.
345          * Legacy advertisements can be both connectable and scannable. Non-legacy
346          * advertisements can be only scannable or only connectable.
347          *
348          * @param connectable Controls whether the advertisement type will be connectable (true) or
349          * non-connectable (false).
350          */
setConnectable(boolean connectable)351         public Builder setConnectable(boolean connectable) {
352             mConnectable = connectable;
353             return this;
354         }
355 
356         /**
357          * Set whether the advertisement type should be discoverable or non-discoverable. By
358          * default, advertisements will be discoverable. Devices connecting to non-discoverable
359          * advertisements cannot initiate bonding.
360          *
361          * @param discoverable Controls whether the advertisement type will be discoverable
362          * ({@code true}) or non-discoverable ({@code false}).
363          */
setDiscoverable(boolean discoverable)364         public @NonNull Builder setDiscoverable(boolean discoverable) {
365             mDiscoverable = discoverable;
366             return this;
367         }
368 
369         /**
370          * Set whether the advertisement type should be scannable.
371          * Legacy advertisements can be both connectable and scannable. Non-legacy
372          * advertisements can be only scannable or only connectable.
373          *
374          * @param scannable Controls whether the advertisement type will be scannable (true) or
375          * non-scannable (false).
376          */
setScannable(boolean scannable)377         public Builder setScannable(boolean scannable) {
378             mScannable = scannable;
379             return this;
380         }
381 
382         /**
383          * When set to true, advertising set will advertise 4.x Spec compliant
384          * advertisements.
385          *
386          * @param isLegacy whether legacy advertising mode should be used.
387          */
setLegacyMode(boolean isLegacy)388         public Builder setLegacyMode(boolean isLegacy) {
389             mIsLegacy = isLegacy;
390             return this;
391         }
392 
393         /**
394          * Set whether advertiser address should be ommited from all packets. If this
395          * mode is used, periodic advertising can't be enabled for this set.
396          *
397          * This is used only if legacy mode is not used.
398          *
399          * @param isAnonymous whether anonymous advertising should be used.
400          */
setAnonymous(boolean isAnonymous)401         public Builder setAnonymous(boolean isAnonymous) {
402             mIsAnonymous = isAnonymous;
403             return this;
404         }
405 
406         /**
407          * Set whether TX power should be included in the extended header.
408          *
409          * This is used only if legacy mode is not used.
410          *
411          * @param includeTxPower whether TX power should be included in extended header
412          */
setIncludeTxPower(boolean includeTxPower)413         public Builder setIncludeTxPower(boolean includeTxPower) {
414             mIncludeTxPower = includeTxPower;
415             return this;
416         }
417 
418         /**
419          * Set the primary physical channel used for this advertising set.
420          *
421          * This is used only if legacy mode is not used.
422          *
423          * Use {@link BluetoothAdapter#isLeCodedPhySupported} to determine if LE Coded PHY is
424          * supported on this device.
425          *
426          * @param primaryPhy Primary advertising physical channel, can only be {@link
427          * BluetoothDevice#PHY_LE_1M} or {@link BluetoothDevice#PHY_LE_CODED}.
428          * @throws IllegalArgumentException If the primaryPhy is invalid.
429          */
setPrimaryPhy(int primaryPhy)430         public Builder setPrimaryPhy(int primaryPhy) {
431             if (primaryPhy != BluetoothDevice.PHY_LE_1M
432                     && primaryPhy != BluetoothDevice.PHY_LE_CODED) {
433                 throw new IllegalArgumentException("bad primaryPhy " + primaryPhy);
434             }
435             mPrimaryPhy = primaryPhy;
436             return this;
437         }
438 
439         /**
440          * Set the secondary physical channel used for this advertising set.
441          *
442          * This is used only if legacy mode is not used.
443          *
444          * Use {@link BluetoothAdapter#isLeCodedPhySupported} and
445          * {@link BluetoothAdapter#isLe2MPhySupported} to determine if LE Coded PHY or 2M PHY is
446          * supported on this device.
447          *
448          * @param secondaryPhy Secondary advertising physical channel, can only be one of {@link
449          * BluetoothDevice#PHY_LE_1M}, {@link BluetoothDevice#PHY_LE_2M} or {@link
450          * BluetoothDevice#PHY_LE_CODED}.
451          * @throws IllegalArgumentException If the secondaryPhy is invalid.
452          */
setSecondaryPhy(int secondaryPhy)453         public Builder setSecondaryPhy(int secondaryPhy) {
454             if (secondaryPhy != BluetoothDevice.PHY_LE_1M
455                     && secondaryPhy != BluetoothDevice.PHY_LE_2M
456                     && secondaryPhy != BluetoothDevice.PHY_LE_CODED) {
457                 throw new IllegalArgumentException("bad secondaryPhy " + secondaryPhy);
458             }
459             mSecondaryPhy = secondaryPhy;
460             return this;
461         }
462 
463         /**
464          * Set advertising interval.
465          *
466          * @param interval Bluetooth LE Advertising interval, in 0.625ms unit. Valid range is from
467          * 160 (100ms) to 16777215 (10,485.759375 s). Recommended values are: {@link
468          * AdvertisingSetParameters#INTERVAL_LOW}, {@link AdvertisingSetParameters#INTERVAL_MEDIUM},
469          * or {@link AdvertisingSetParameters#INTERVAL_HIGH}.
470          * @throws IllegalArgumentException If the interval is invalid.
471          */
setInterval(int interval)472         public Builder setInterval(int interval) {
473             if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) {
474                 throw new IllegalArgumentException("unknown interval " + interval);
475             }
476             mInterval = interval;
477             return this;
478         }
479 
480         /**
481          * Set the transmission power level for the advertising.
482          *
483          * @param txPowerLevel Transmission power of Bluetooth LE Advertising, in dBm. The valid
484          * range is [-127, 1] Recommended values are:
485          * {@link AdvertisingSetParameters#TX_POWER_ULTRA_LOW},
486          * {@link AdvertisingSetParameters#TX_POWER_LOW},
487          * {@link AdvertisingSetParameters#TX_POWER_MEDIUM},
488          * or {@link AdvertisingSetParameters#TX_POWER_HIGH}.
489          * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid.
490          */
setTxPowerLevel(int txPowerLevel)491         public Builder setTxPowerLevel(int txPowerLevel) {
492             if (txPowerLevel < TX_POWER_MIN || txPowerLevel > TX_POWER_MAX) {
493                 throw new IllegalArgumentException("unknown txPowerLevel " + txPowerLevel);
494             }
495             mTxPowerLevel = txPowerLevel;
496             return this;
497         }
498 
499         /**
500          * Set own address type for advertising to control public or privacy mode. If used to set
501          * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT},
502          * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the
503          * time of starting advertising.
504          *
505          * @throws IllegalArgumentException If the {@code ownAddressType} is invalid
506          *
507          * @hide
508          */
509         @SystemApi
setOwnAddressType(@ddressTypeStatus int ownAddressType)510         public @NonNull Builder setOwnAddressType(@AddressTypeStatus int ownAddressType) {
511             if (ownAddressType < AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT
512                     || ownAddressType
513                             > AdvertisingSetParameters.ADDRESS_TYPE_RANDOM_NON_RESOLVABLE) {
514                 throw new IllegalArgumentException("unknown address type " + ownAddressType);
515             }
516             mOwnAddressType = ownAddressType;
517             return this;
518         }
519 
520         /**
521          * Build the {@link AdvertisingSetParameters} object.
522          *
523          * @throws IllegalStateException if invalid combination of parameters is used.
524          */
build()525         public AdvertisingSetParameters build() {
526             if (mIsLegacy) {
527                 if (mIsAnonymous) {
528                     throw new IllegalArgumentException("Legacy advertising can't be anonymous");
529                 }
530 
531                 if (mConnectable && !mScannable) {
532                     throw new IllegalStateException(
533                             "Legacy advertisement can't be connectable and non-scannable");
534                 }
535 
536                 if (mIncludeTxPower) {
537                     throw new IllegalStateException(
538                             "Legacy advertising can't include TX power level in header");
539                 }
540             } else {
541                 if (mConnectable && mScannable) {
542                     throw new IllegalStateException(
543                             "Advertising can't be both connectable and scannable");
544                 }
545 
546                 if (mIsAnonymous && mConnectable) {
547                     throw new IllegalStateException(
548                             "Advertising can't be both connectable and anonymous");
549                 }
550             }
551 
552             return new AdvertisingSetParameters(
553                     mConnectable,
554                     mDiscoverable,
555                     mScannable,
556                     mIsLegacy,
557                     mIsAnonymous,
558                     mIncludeTxPower,
559                     mPrimaryPhy,
560                     mSecondaryPhy,
561                     mInterval,
562                     mTxPowerLevel,
563                     mOwnAddressType);
564         }
565     }
566 }
567