AdvertiseData.java revision 67c01a4b6d890212fb4647973a627e25a3a9788b
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
17package android.bluetooth.le;
18
19import android.annotation.Nullable;
20import android.bluetooth.BluetoothUuid;
21import android.os.Parcel;
22import android.os.ParcelUuid;
23import android.os.Parcelable;
24
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.List;
28import java.util.Objects;
29
30/**
31 * Advertise data packet container for Bluetooth LE advertising. This represents the data to be
32 * advertised as well as the scan response data for active scans.
33 * <p>
34 * Use {@link AdvertiseData.Builder} to create an instance of {@link AdvertiseData} to be
35 * advertised.
36 *
37 * @see BluetoothLeAdvertiser
38 * @see ScanRecord
39 */
40public final class AdvertiseData implements Parcelable {
41
42    @Nullable
43    private final List<ParcelUuid> mServiceUuids;
44
45    private final int mManufacturerId;
46    @Nullable
47    private final byte[] mManufacturerSpecificData;
48
49    @Nullable
50    private final ParcelUuid mServiceDataUuid;
51    @Nullable
52    private final byte[] mServiceData;
53
54    private final boolean mIncludeTxPowerLevel;
55    private final boolean mIncludeDeviceName;
56
57    private AdvertiseData(List<ParcelUuid> serviceUuids,
58            ParcelUuid serviceDataUuid, byte[] serviceData,
59            int manufacturerId,
60            byte[] manufacturerSpecificData, boolean includeTxPowerLevel,
61            boolean includeDeviceName) {
62        mServiceUuids = serviceUuids;
63        mManufacturerId = manufacturerId;
64        mManufacturerSpecificData = manufacturerSpecificData;
65        mServiceDataUuid = serviceDataUuid;
66        mServiceData = serviceData;
67        mIncludeTxPowerLevel = includeTxPowerLevel;
68        mIncludeDeviceName = includeDeviceName;
69    }
70
71    /**
72     * Returns a list of service UUIDs within the advertisement that are used to identify the
73     * Bluetooth GATT services.
74     */
75    public List<ParcelUuid> getServiceUuids() {
76        return mServiceUuids;
77    }
78
79    /**
80     * Returns the manufacturer identifier, which is a non-negative number assigned by Bluetooth
81     * SIG.
82     */
83    public int getManufacturerId() {
84        return mManufacturerId;
85    }
86
87    /**
88     * Returns the manufacturer specific data which is the content of manufacturer specific data
89     * field. The first 2 bytes of the data contain the company id.
90     */
91    public byte[] getManufacturerSpecificData() {
92        return mManufacturerSpecificData;
93    }
94
95    /**
96     * Returns a 16-bit UUID of the service that the service data is associated with.
97     */
98    public ParcelUuid getServiceDataUuid() {
99        return mServiceDataUuid;
100    }
101
102    /**
103     * Returns service data.
104     */
105    public byte[] getServiceData() {
106        return mServiceData;
107    }
108
109    /**
110     * Whether the transmission power level will be included in the advertisement packet.
111     */
112    public boolean getIncludeTxPowerLevel() {
113        return mIncludeTxPowerLevel;
114    }
115
116    /**
117     * Whether the device name will be included in the advertisement packet.
118     */
119    public boolean getIncludeDeviceName() {
120        return mIncludeDeviceName;
121    }
122
123    /**
124     * @hide
125     */
126    @Override
127    public int hashCode() {
128        return Objects.hash(mServiceUuids, mManufacturerId, mManufacturerSpecificData,
129                mServiceDataUuid, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
130    }
131
132    /**
133     * @hide
134     */
135    @Override
136    public boolean equals(Object obj) {
137        if (this == obj) {
138            return true;
139        }
140        if (obj == null || getClass() != obj.getClass()) {
141            return false;
142        }
143        AdvertiseData other = (AdvertiseData) obj;
144        return Objects.equals(mServiceUuids, other.mServiceUuids) &&
145                mManufacturerId == other.mManufacturerId &&
146                Objects.deepEquals(mManufacturerSpecificData, other.mManufacturerSpecificData) &&
147                Objects.equals(mServiceDataUuid, other.mServiceDataUuid) &&
148                Objects.deepEquals(mServiceData, other.mServiceData) &&
149                        mIncludeDeviceName == other.mIncludeDeviceName &&
150                        mIncludeTxPowerLevel == other.mIncludeTxPowerLevel;
151    }
152
153    @Override
154    public String toString() {
155        return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerId="
156                + mManufacturerId + ", mManufacturerSpecificData="
157                + Arrays.toString(mManufacturerSpecificData) + ", mServiceDataUuid="
158                + mServiceDataUuid + ", mServiceData=" + Arrays.toString(mServiceData)
159                + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
160                + mIncludeDeviceName + "]";
161    }
162
163    @Override
164    public int describeContents() {
165        return 0;
166    }
167
168    @Override
169    public void writeToParcel(Parcel dest, int flags) {
170        dest.writeList(mServiceUuids);
171
172        dest.writeInt(mManufacturerId);
173        if (mManufacturerSpecificData == null) {
174            dest.writeInt(0);
175        } else {
176            dest.writeInt(1);
177            dest.writeInt(mManufacturerSpecificData.length);
178            dest.writeByteArray(mManufacturerSpecificData);
179        }
180        dest.writeParcelable(mServiceDataUuid, flags);
181        if (mServiceData == null) {
182            dest.writeInt(0);
183        } else {
184            dest.writeInt(1);
185            dest.writeInt(mServiceData.length);
186            dest.writeByteArray(mServiceData);
187        }
188        dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0));
189        dest.writeByte((byte) (getIncludeDeviceName() ? 1 : 0));
190    }
191
192    /**
193     * @hide
194     */
195    public static final Parcelable.Creator<AdvertiseData> CREATOR =
196            new Creator<AdvertiseData>() {
197            @Override
198                public AdvertiseData[] newArray(int size) {
199                    return new AdvertiseData[size];
200                }
201
202            @Override
203                public AdvertiseData createFromParcel(Parcel in) {
204                    Builder builder = new Builder();
205                    @SuppressWarnings("unchecked")
206                    List<ParcelUuid> uuids = in.readArrayList(ParcelUuid.class.getClassLoader());
207                    if (uuids != null) {
208                        for (ParcelUuid uuid : uuids) {
209                            builder.addServiceUuid(uuid);
210                        }
211                    }
212                    int manufacturerId = in.readInt();
213                    if (in.readInt() == 1) {
214                        int manufacturerDataLength = in.readInt();
215                        byte[] manufacturerData = new byte[manufacturerDataLength];
216                        in.readByteArray(manufacturerData);
217                        builder.setManufacturerData(manufacturerId, manufacturerData);
218                    }
219                    ParcelUuid serviceDataUuid = in.readParcelable(
220                            ParcelUuid.class.getClassLoader());
221                    if (in.readInt() == 1) {
222                        int serviceDataLength = in.readInt();
223                        byte[] serviceData = new byte[serviceDataLength];
224                        in.readByteArray(serviceData);
225                        builder.setServiceData(serviceDataUuid, serviceData);
226                    }
227                    builder.setIncludeTxPowerLevel(in.readByte() == 1);
228                    builder.setIncludeDeviceName(in.readByte() == 1);
229                    return builder.build();
230                }
231            };
232
233    /**
234     * Builder for {@link AdvertiseData}.
235     */
236    public static final class Builder {
237        @Nullable
238        private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
239        private int mManufacturerId = -1;
240        @Nullable
241        private byte[] mManufacturerSpecificData;
242        @Nullable
243        private ParcelUuid mServiceDataUuid;
244        @Nullable
245        private byte[] mServiceData;
246        private boolean mIncludeTxPowerLevel;
247        private boolean mIncludeDeviceName;
248
249        /**
250         * Add a service UUID to advertise data.
251         *
252         * @param serviceUuid A service UUID to be advertised.
253         * @throws IllegalArgumentException If the {@code serviceUuids} are null.
254         */
255        public Builder addServiceUuid(ParcelUuid serviceUuid) {
256            if (serviceUuid == null) {
257                throw new IllegalArgumentException("serivceUuids are null");
258            }
259            mServiceUuids.add(serviceUuid);
260            return this;
261        }
262
263        /**
264         * Add service data to advertise data.
265         *
266         * @param serviceDataUuid 16-bit UUID of the service the data is associated with
267         * @param serviceData Service data
268         * @throws IllegalArgumentException If the {@code serviceDataUuid} or {@code serviceData} is
269         *             empty.
270         */
271        public Builder setServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) {
272            if (serviceDataUuid == null || serviceData == null) {
273                throw new IllegalArgumentException(
274                        "serviceDataUuid or serviceDataUuid is null");
275            }
276            mServiceDataUuid = serviceDataUuid;
277            mServiceData = serviceData;
278            return this;
279        }
280
281        /**
282         * Set manufacturer specific data.
283         * <p>
284         * Please refer to the Bluetooth Assigned Numbers document provided by the <a
285         * href="https://www.bluetooth.org">Bluetooth SIG</a> for a list of existing company
286         * identifiers.
287         *
288         * @param manufacturerId Manufacturer ID assigned by Bluetooth SIG.
289         * @param manufacturerSpecificData Manufacturer specific data
290         * @throws IllegalArgumentException If the {@code manufacturerId} is negative or
291         *             {@code manufacturerSpecificData} is null.
292         */
293        public Builder setManufacturerData(int manufacturerId, byte[] manufacturerSpecificData) {
294            if (manufacturerId < 0) {
295                throw new IllegalArgumentException(
296                        "invalid manufacturerId - " + manufacturerId);
297            }
298            if (manufacturerSpecificData == null) {
299                throw new IllegalArgumentException("manufacturerSpecificData is null");
300            }
301            mManufacturerId = manufacturerId;
302            mManufacturerSpecificData = manufacturerSpecificData;
303            return this;
304        }
305
306        /**
307         * Whether the transmission power level should be included in the advertise packet. Tx power
308         * level field takes 3 bytes in advertise packet.
309         */
310        public Builder setIncludeTxPowerLevel(boolean includeTxPowerLevel) {
311            mIncludeTxPowerLevel = includeTxPowerLevel;
312            return this;
313        }
314
315        /**
316         * Set whether the device name should be included in advertise packet.
317         */
318        public Builder setIncludeDeviceName(boolean includeDeviceName) {
319            mIncludeDeviceName = includeDeviceName;
320            return this;
321        }
322
323        /**
324         * Build the {@link AdvertiseData}.
325         */
326        public AdvertiseData build() {
327            return new AdvertiseData(mServiceUuids,
328                    mServiceDataUuid,
329                    mServiceData, mManufacturerId, mManufacturerSpecificData,
330                    mIncludeTxPowerLevel, mIncludeDeviceName);
331        }
332    }
333}
334