1 /*
2  * Copyright (C) 2013 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 package android.bluetooth;
17 
18 import android.annotation.NonNull;
19 import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.os.Build;
22 import android.os.Parcel;
23 import android.os.ParcelUuid;
24 import android.os.Parcelable;
25 
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.UUID;
29 
30 /**
31  * Represents a Bluetooth GATT Service
32  *
33  * <p>Gatt Service contains a collection of {@link BluetoothGattCharacteristic}, as well as
34  * referenced services.
35  */
36 public class BluetoothGattService implements Parcelable {
37 
38     /** Primary service */
39     public static final int SERVICE_TYPE_PRIMARY = 0;
40 
41     /** Secondary service (included by primary services) */
42     public static final int SERVICE_TYPE_SECONDARY = 1;
43 
44     /**
45      * The remote device this service is associated with. This applies to client applications only.
46      *
47      * @hide
48      */
49     @UnsupportedAppUsage protected BluetoothDevice mDevice;
50 
51     /**
52      * The UUID of this service.
53      *
54      * @hide
55      */
56     protected UUID mUuid;
57 
58     /**
59      * Instance ID for this service.
60      *
61      * @hide
62      */
63     protected int mInstanceId;
64 
65     /**
66      * Handle counter override (for conformance testing).
67      *
68      * @hide
69      */
70     protected int mHandles = 0;
71 
72     /**
73      * Service type (Primary/Secondary).
74      *
75      * @hide
76      */
77     protected int mServiceType;
78 
79     /** List of characteristics included in this service. */
80     protected List<BluetoothGattCharacteristic> mCharacteristics;
81 
82     /** List of included services for this service. */
83     protected List<BluetoothGattService> mIncludedServices;
84 
85     /** Whether the service uuid should be advertised. */
86     private boolean mAdvertisePreferred;
87 
88     /**
89      * Create a new BluetoothGattService.
90      *
91      * @param uuid The UUID for this service
92      * @param serviceType The type of this service, {@link
93      *     BluetoothGattService#SERVICE_TYPE_PRIMARY} or {@link
94      *     BluetoothGattService#SERVICE_TYPE_SECONDARY}
95      */
BluetoothGattService(UUID uuid, int serviceType)96     public BluetoothGattService(UUID uuid, int serviceType) {
97         mDevice = null;
98         mUuid = uuid;
99         mInstanceId = 0;
100         mServiceType = serviceType;
101         mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
102         mIncludedServices = new ArrayList<BluetoothGattService>();
103     }
104 
105     /**
106      * Create a new BluetoothGattService
107      *
108      * @hide
109      */
BluetoothGattService( BluetoothDevice device, UUID uuid, int instanceId, int serviceType)110     /*package*/ BluetoothGattService(
111             BluetoothDevice device, UUID uuid, int instanceId, int serviceType) {
112         mDevice = device;
113         mUuid = uuid;
114         mInstanceId = instanceId;
115         mServiceType = serviceType;
116         mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
117         mIncludedServices = new ArrayList<BluetoothGattService>();
118     }
119 
120     /**
121      * Create a new BluetoothGattService
122      *
123      * @hide
124      */
BluetoothGattService(UUID uuid, int instanceId, int serviceType)125     public BluetoothGattService(UUID uuid, int instanceId, int serviceType) {
126         mDevice = null;
127         mUuid = uuid;
128         mInstanceId = instanceId;
129         mServiceType = serviceType;
130         mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
131         mIncludedServices = new ArrayList<BluetoothGattService>();
132     }
133 
134     /** @hide */
describeContents()135     public int describeContents() {
136         return 0;
137     }
138 
139     @Override
writeToParcel(Parcel out, int flags)140     public void writeToParcel(Parcel out, int flags) {
141         out.writeParcelable(new ParcelUuid(mUuid), 0);
142         out.writeInt(mInstanceId);
143         out.writeInt(mServiceType);
144         out.writeTypedList(mCharacteristics);
145 
146         ArrayList<BluetoothGattIncludedService> includedServices =
147                 new ArrayList<BluetoothGattIncludedService>(mIncludedServices.size());
148         for (BluetoothGattService s : mIncludedServices) {
149             includedServices.add(
150                     new BluetoothGattIncludedService(s.getUuid(), s.getInstanceId(), s.getType()));
151         }
152         out.writeTypedList(includedServices);
153     }
154 
155     public static final @NonNull Creator<BluetoothGattService> CREATOR =
156             new Creator<>() {
157                 public BluetoothGattService createFromParcel(Parcel in) {
158                     return new BluetoothGattService(in);
159                 }
160 
161                 public BluetoothGattService[] newArray(int size) {
162                     return new BluetoothGattService[size];
163                 }
164             };
165 
BluetoothGattService(Parcel in)166     private BluetoothGattService(Parcel in) {
167         mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
168         mInstanceId = in.readInt();
169         mServiceType = in.readInt();
170 
171         mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
172 
173         ArrayList<BluetoothGattCharacteristic> chrcs =
174                 in.createTypedArrayList(BluetoothGattCharacteristic.CREATOR);
175         if (chrcs != null) {
176             for (BluetoothGattCharacteristic chrc : chrcs) {
177                 chrc.setService(this);
178                 mCharacteristics.add(chrc);
179             }
180         }
181 
182         mIncludedServices = new ArrayList<BluetoothGattService>();
183 
184         ArrayList<BluetoothGattIncludedService> inclSvcs =
185                 in.createTypedArrayList(BluetoothGattIncludedService.CREATOR);
186         if (chrcs != null) {
187             for (BluetoothGattIncludedService isvc : inclSvcs) {
188                 mIncludedServices.add(
189                         new BluetoothGattService(
190                                 null, isvc.getUuid(), isvc.getInstanceId(), isvc.getType()));
191             }
192         }
193     }
194 
195     /**
196      * Returns the device associated with this service.
197      *
198      * @hide
199      */
getDevice()200     /*package*/ BluetoothDevice getDevice() {
201         return mDevice;
202     }
203 
204     /**
205      * Returns the device associated with this service.
206      *
207      * @hide
208      */
setDevice(BluetoothDevice device)209     /*package*/ void setDevice(BluetoothDevice device) {
210         mDevice = device;
211     }
212 
213     /**
214      * Add an included service to this service.
215      *
216      * @param service The service to be added
217      * @return true, if the included service was added to the service
218      */
219     @RequiresLegacyBluetoothPermission
addService(BluetoothGattService service)220     public boolean addService(BluetoothGattService service) {
221         mIncludedServices.add(service);
222         return true;
223     }
224 
225     /**
226      * Add a characteristic to this service.
227      *
228      * @param characteristic The characteristics to be added
229      * @return true, if the characteristic was added to the service
230      */
231     @RequiresLegacyBluetoothPermission
addCharacteristic(BluetoothGattCharacteristic characteristic)232     public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) {
233         mCharacteristics.add(characteristic);
234         characteristic.setService(this);
235         return true;
236     }
237 
238     /**
239      * Get characteristic by UUID and instanceId.
240      *
241      * @hide
242      */
getCharacteristic(UUID uuid, int instanceId)243     /*package*/ BluetoothGattCharacteristic getCharacteristic(UUID uuid, int instanceId) {
244         for (BluetoothGattCharacteristic characteristic : mCharacteristics) {
245             if (uuid.equals(characteristic.getUuid())
246                     && characteristic.getInstanceId() == instanceId) {
247                 return characteristic;
248             }
249         }
250         return null;
251     }
252 
253     /**
254      * Force the instance ID.
255      *
256      * @hide
257      */
258     @UnsupportedAppUsage
setInstanceId(int instanceId)259     public void setInstanceId(int instanceId) {
260         mInstanceId = instanceId;
261     }
262 
263     /**
264      * Get the handle count override (conformance testing.
265      *
266      * @hide
267      */
getHandles()268     /*package*/ int getHandles() {
269         return mHandles;
270     }
271 
272     /**
273      * Force the number of handles to reserve for this service. This is needed for conformance
274      * testing only.
275      *
276      * @hide
277      */
setHandles(int handles)278     public void setHandles(int handles) {
279         mHandles = handles;
280     }
281 
282     /**
283      * Add an included service to the internal map.
284      *
285      * @hide
286      */
addIncludedService(BluetoothGattService includedService)287     public void addIncludedService(BluetoothGattService includedService) {
288         mIncludedServices.add(includedService);
289     }
290 
291     /**
292      * Returns the UUID of this service
293      *
294      * @return UUID of this service
295      */
getUuid()296     public UUID getUuid() {
297         return mUuid;
298     }
299 
300     /**
301      * Returns the instance ID for this service
302      *
303      * <p>If a remote device offers multiple services with the same UUID (ex. multiple battery
304      * services for different batteries), the instance ID is used to distuinguish services.
305      *
306      * @return Instance ID of this service
307      */
getInstanceId()308     public int getInstanceId() {
309         return mInstanceId;
310     }
311 
312     /** Get the type of this service (primary/secondary) */
getType()313     public int getType() {
314         return mServiceType;
315     }
316 
317     /**
318      * Get the list of included GATT services for this service.
319      *
320      * @return List of included services or empty list if no included services were discovered.
321      */
getIncludedServices()322     public List<BluetoothGattService> getIncludedServices() {
323         return mIncludedServices;
324     }
325 
326     /**
327      * Returns a list of characteristics included in this service.
328      *
329      * @return Characteristics included in this service
330      */
getCharacteristics()331     public List<BluetoothGattCharacteristic> getCharacteristics() {
332         return mCharacteristics;
333     }
334 
335     /**
336      * Returns a characteristic with a given UUID out of the list of characteristics offered by this
337      * service.
338      *
339      * <p>This is a convenience function to allow access to a given characteristic without
340      * enumerating over the list returned by {@link #getCharacteristics} manually.
341      *
342      * <p>If a remote service offers multiple characteristics with the same UUID, the first instance
343      * of a characteristic with the given UUID is returned.
344      *
345      * @return GATT characteristic object or null if no characteristic with the given UUID was
346      *     found.
347      */
getCharacteristic(UUID uuid)348     public BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
349         for (BluetoothGattCharacteristic characteristic : mCharacteristics) {
350             if (uuid.equals(characteristic.getUuid())) {
351                 return characteristic;
352             }
353         }
354         return null;
355     }
356 
357     /**
358      * Returns whether the uuid of the service should be advertised.
359      *
360      * @hide
361      */
isAdvertisePreferred()362     public boolean isAdvertisePreferred() {
363         return mAdvertisePreferred;
364     }
365 
366     /**
367      * Set whether the service uuid should be advertised.
368      *
369      * @hide
370      */
371     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setAdvertisePreferred(boolean advertisePreferred)372     public void setAdvertisePreferred(boolean advertisePreferred) {
373         mAdvertisePreferred = advertisePreferred;
374     }
375 }
376