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