1 /*
2  * Copyright (C) 2014 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.NonNull;
20 import android.annotation.SystemApi;
21 import android.bluetooth.le.AdvertisingSetParameters.AddressTypeStatus;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.util.Log;
25 
26 /**
27  * The {@link AdvertiseSettings} provide a way to adjust advertising preferences for each Bluetooth
28  * LE advertisement instance. Use {@link AdvertiseSettings.Builder} to create an instance of this
29  * class.
30  */
31 public final class AdvertiseSettings implements Parcelable {
32     private static final String TAG = AdvertiseSettings.class.getSimpleName();
33 
34     /**
35      * Perform Bluetooth LE advertising in low power mode. This is the default and preferred
36      * advertising mode as it consumes the least power.
37      */
38     public static final int ADVERTISE_MODE_LOW_POWER = 0;
39 
40     /**
41      * Perform Bluetooth LE advertising in balanced power mode. This is balanced between advertising
42      * frequency and power consumption.
43      */
44     public static final int ADVERTISE_MODE_BALANCED = 1;
45 
46     /**
47      * Perform Bluetooth LE advertising in low latency, high power mode. This has the highest power
48      * consumption and should not be used for continuous background advertising.
49      */
50     public static final int ADVERTISE_MODE_LOW_LATENCY = 2;
51 
52     /**
53      * Advertise using the lowest transmission (TX) power level. Low transmission power can be used
54      * to restrict the visibility range of advertising packets.
55      */
56     public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0;
57 
58     /** Advertise using low TX power level. */
59     public static final int ADVERTISE_TX_POWER_LOW = 1;
60 
61     /** Advertise using medium TX power level. */
62     public static final int ADVERTISE_TX_POWER_MEDIUM = 2;
63 
64     /**
65      * Advertise using high TX power level. This corresponds to largest visibility range of the
66      * advertising packet.
67      */
68     public static final int ADVERTISE_TX_POWER_HIGH = 3;
69 
70     /** The maximum limited advertisement duration as specified by the Bluetooth SIG */
71     private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000;
72 
73     private final int mAdvertiseMode;
74     private final int mAdvertiseTxPowerLevel;
75     private final int mAdvertiseTimeoutMillis;
76     private final boolean mAdvertiseConnectable;
77     private final boolean mAdvertiseDiscoverable;
78     private final int mOwnAddressType;
79 
AdvertiseSettings( int advertiseMode, int advertiseTxPowerLevel, boolean advertiseConnectable, boolean discoverable, int advertiseTimeout, @AddressTypeStatus int ownAddressType)80     private AdvertiseSettings(
81             int advertiseMode,
82             int advertiseTxPowerLevel,
83             boolean advertiseConnectable,
84             boolean discoverable,
85             int advertiseTimeout,
86             @AddressTypeStatus int ownAddressType) {
87         mAdvertiseMode = advertiseMode;
88         mAdvertiseTxPowerLevel = advertiseTxPowerLevel;
89         mAdvertiseConnectable = advertiseConnectable;
90         mAdvertiseDiscoverable = discoverable;
91         mAdvertiseTimeoutMillis = advertiseTimeout;
92         mOwnAddressType = ownAddressType;
93     }
94 
AdvertiseSettings(Parcel in)95     private AdvertiseSettings(Parcel in) {
96         mAdvertiseMode = in.readInt();
97         mAdvertiseTxPowerLevel = in.readInt();
98         mAdvertiseConnectable = in.readInt() != 0;
99         mAdvertiseTimeoutMillis = in.readInt();
100         mOwnAddressType = in.readInt();
101         mAdvertiseDiscoverable = in.readInt() != 0;
102     }
103 
104     /** Returns the advertise mode. */
getMode()105     public int getMode() {
106         return mAdvertiseMode;
107     }
108 
109     /** Returns the TX power level for advertising. */
getTxPowerLevel()110     public int getTxPowerLevel() {
111         return mAdvertiseTxPowerLevel;
112     }
113 
114     /** Returns whether the advertisement will indicate connectable. */
isConnectable()115     public boolean isConnectable() {
116         return mAdvertiseConnectable;
117     }
118 
119     /** Returns whether the advertisement will be discoverable. */
isDiscoverable()120     public boolean isDiscoverable() {
121         return mAdvertiseDiscoverable;
122     }
123 
124     /** Returns the advertising time limit in milliseconds. */
getTimeout()125     public int getTimeout() {
126         return mAdvertiseTimeoutMillis;
127     }
128 
129     /**
130      * @return the own address type for advertising
131      * @hide
132      */
133     @SystemApi
getOwnAddressType()134     public @AddressTypeStatus int getOwnAddressType() {
135         return mOwnAddressType;
136     }
137 
138     @Override
toString()139     public String toString() {
140         return "Settings [mAdvertiseMode="
141                 + mAdvertiseMode
142                 + ", mAdvertiseTxPowerLevel="
143                 + mAdvertiseTxPowerLevel
144                 + ", mAdvertiseConnectable="
145                 + mAdvertiseConnectable
146                 + ", mAdvertiseDiscoverable="
147                 + mAdvertiseDiscoverable
148                 + ", mAdvertiseTimeoutMillis="
149                 + mAdvertiseTimeoutMillis
150                 + ", mOwnAddressType="
151                 + mOwnAddressType
152                 + "]";
153     }
154 
155     @Override
describeContents()156     public int describeContents() {
157         return 0;
158     }
159 
160     @Override
writeToParcel(Parcel dest, int flags)161     public void writeToParcel(Parcel dest, int flags) {
162         dest.writeInt(mAdvertiseMode);
163         dest.writeInt(mAdvertiseTxPowerLevel);
164         dest.writeInt(mAdvertiseConnectable ? 1 : 0);
165         dest.writeInt(mAdvertiseTimeoutMillis);
166         dest.writeInt(mOwnAddressType);
167         dest.writeInt(mAdvertiseDiscoverable ? 1 : 0);
168     }
169 
170     public static final @android.annotation.NonNull Parcelable.Creator<AdvertiseSettings> CREATOR =
171             new Creator<AdvertiseSettings>() {
172                 @Override
173                 public AdvertiseSettings[] newArray(int size) {
174                     return new AdvertiseSettings[size];
175                 }
176 
177                 @Override
178                 public AdvertiseSettings createFromParcel(Parcel in) {
179                     return new AdvertiseSettings(in);
180                 }
181             };
182 
183     /** Builder class for {@link AdvertiseSettings}. */
184     public static final class Builder {
185         private int mMode = ADVERTISE_MODE_LOW_POWER;
186         private int mTxPowerLevel = ADVERTISE_TX_POWER_MEDIUM;
187         private int mTimeoutMillis = 0;
188         private boolean mConnectable = true;
189         private boolean mDiscoverable = true;
190         private int mOwnAddressType = AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT;
191 
192         /**
193          * Set advertise mode to control the advertising power and latency.
194          *
195          * @param advertiseMode Bluetooth LE Advertising mode, can only be one of {@link
196          *     AdvertiseSettings#ADVERTISE_MODE_LOW_POWER}, {@link
197          *     AdvertiseSettings#ADVERTISE_MODE_BALANCED}, or {@link
198          *     AdvertiseSettings#ADVERTISE_MODE_LOW_LATENCY}.
199          * @throws IllegalArgumentException If the advertiseMode is invalid.
200          */
setAdvertiseMode(int advertiseMode)201         public Builder setAdvertiseMode(int advertiseMode) {
202             if (advertiseMode < ADVERTISE_MODE_LOW_POWER
203                     || advertiseMode > ADVERTISE_MODE_LOW_LATENCY) {
204                 throw new IllegalArgumentException("unknown mode " + advertiseMode);
205             }
206             mMode = advertiseMode;
207             return this;
208         }
209 
210         /**
211          * Set advertise TX power level to control the transmission power level for the advertising.
212          *
213          * @param txPowerLevel Transmission power of Bluetooth LE Advertising, can only be one of
214          *     {@link AdvertiseSettings#ADVERTISE_TX_POWER_ULTRA_LOW}, {@link
215          *     AdvertiseSettings#ADVERTISE_TX_POWER_LOW}, {@link
216          *     AdvertiseSettings#ADVERTISE_TX_POWER_MEDIUM} or {@link
217          *     AdvertiseSettings#ADVERTISE_TX_POWER_HIGH}.
218          * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid.
219          */
setTxPowerLevel(int txPowerLevel)220         public Builder setTxPowerLevel(int txPowerLevel) {
221             if (txPowerLevel < ADVERTISE_TX_POWER_ULTRA_LOW
222                     || txPowerLevel > ADVERTISE_TX_POWER_HIGH) {
223                 throw new IllegalArgumentException("unknown tx power level " + txPowerLevel);
224             }
225             Log.d(TAG, "setTxPowerLevel: " + txPowerLevel);
226             mTxPowerLevel = txPowerLevel;
227             return this;
228         }
229 
230         /**
231          * Set whether the advertisement type should be connectable or non-connectable.
232          *
233          * @param connectable Controls whether the advertisement type will be connectable (true) or
234          *     non-connectable (false).
235          */
setConnectable(boolean connectable)236         public Builder setConnectable(boolean connectable) {
237             mConnectable = connectable;
238             return this;
239         }
240 
241         /**
242          * Set whether the advertisement type should be discoverable or non-discoverable.
243          *
244          * @param discoverable Controls whether the advertisement type will be discoverable ({@code
245          *     true}) or non-discoverable ({@code false}).
246          */
setDiscoverable(boolean discoverable)247         public @NonNull Builder setDiscoverable(boolean discoverable) {
248             mDiscoverable = discoverable;
249             return this;
250         }
251 
252         /**
253          * Limit advertising to a given amount of time.
254          *
255          * @param timeoutMillis Advertising time limit. May not exceed 180000 milliseconds. A value
256          *     of 0 will disable the time limit.
257          * @throws IllegalArgumentException If the provided timeout is over 180000 ms.
258          */
setTimeout(int timeoutMillis)259         public Builder setTimeout(int timeoutMillis) {
260             if (timeoutMillis < 0 || timeoutMillis > LIMITED_ADVERTISING_MAX_MILLIS) {
261                 throw new IllegalArgumentException(
262                         "timeoutMillis invalid (must be 0-"
263                                 + LIMITED_ADVERTISING_MAX_MILLIS
264                                 + " milliseconds)");
265             }
266             mTimeoutMillis = timeoutMillis;
267             return this;
268         }
269 
270         /**
271          * Set own address type for advertising to control public or privacy mode. If used to set
272          * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT},
273          * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the time of
274          * starting advertising.
275          *
276          * @throws IllegalArgumentException If the {@code ownAddressType} is invalid
277          * @hide
278          */
279         @SystemApi
setOwnAddressType(@ddressTypeStatus int ownAddressType)280         public @NonNull Builder setOwnAddressType(@AddressTypeStatus int ownAddressType) {
281             if (ownAddressType < AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT
282                     || ownAddressType
283                             > AdvertisingSetParameters.ADDRESS_TYPE_RANDOM_NON_RESOLVABLE) {
284                 throw new IllegalArgumentException("unknown address type " + ownAddressType);
285             }
286             mOwnAddressType = ownAddressType;
287             return this;
288         }
289 
290         /** Build the {@link AdvertiseSettings} object. */
build()291         public AdvertiseSettings build() {
292             return new AdvertiseSettings(
293                     mMode,
294                     mTxPowerLevel,
295                     mConnectable,
296                     mDiscoverable,
297                     mTimeoutMillis,
298                     mOwnAddressType);
299         }
300     }
301 }
302