blob: 0c00c06712a490349aecc1083d0f39efe83d9105 [file] [log] [blame]
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -08001/*
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
17package android.bluetooth;
18
19import android.bluetooth.BluetoothAdapter;
20import android.bluetooth.BluetoothDevice;
21import android.bluetooth.BluetoothProfile;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080022import android.content.Context;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080023import android.os.ParcelUuid;
24import android.os.RemoteException;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080025import android.util.Log;
26
27import java.util.ArrayList;
28import java.util.List;
29import java.util.UUID;
30
31/**
Matthew Xieddf7e472013-03-01 18:41:02 -080032 * Public API for the Bluetooth GATT Profile server role.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080033 *
Matthew Xieddf7e472013-03-01 18:41:02 -080034 * <p>This class provides Bluetooth GATT server role functionality,
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080035 * allowing applications to create and advertise Bluetooth Smart services
36 * and characteristics.
37 *
38 * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
39 * via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
40 * BluetoothGatt proxy object.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080041 */
42public final class BluetoothGattServer implements BluetoothProfile {
43 private static final String TAG = "BluetoothGattServer";
44 private static final boolean DBG = true;
45
Matthew Xieddf7e472013-03-01 18:41:02 -080046 private final Context mContext;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080047 private BluetoothAdapter mAdapter;
48 private IBluetoothGatt mService;
49 private BluetoothGattServerCallback mCallback;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080050
Matthew Xieddf7e472013-03-01 18:41:02 -080051 private Object mServerIfLock = new Object();
52 private int mServerIf;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080053 private List<BluetoothGattService> mServices;
54
Matthew Xieddf7e472013-03-01 18:41:02 -080055 private static final int CALLBACK_REG_TIMEOUT = 10000;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080056
57 /**
58 * Bluetooth GATT interface callbacks
59 */
60 private final IBluetoothGattServerCallback mBluetoothGattServerCallback =
61 new IBluetoothGattServerCallback.Stub() {
62 /**
63 * Application interface registered - app is ready to go
64 * @hide
65 */
66 public void onServerRegistered(int status, int serverIf) {
67 if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status
68 + " serverIf=" + serverIf);
Matthew Xieddf7e472013-03-01 18:41:02 -080069 synchronized(mServerIfLock) {
70 if (mCallback != null) {
71 mServerIf = serverIf;
72 mServerIfLock.notify();
73 } else {
74 // registration timeout
75 Log.e(TAG, "onServerRegistered: mCallback is null");
76 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080077 }
78 }
79
80 /**
81 * Callback reporting an LE scan result.
82 * @hide
83 */
84 public void onScanResult(String address, int rssi, byte[] advData) {
85 if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
Matthew Xieddf7e472013-03-01 18:41:02 -080086 // no op
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080087 }
88
89 /**
90 * Server connection state changed
91 * @hide
92 */
93 public void onServerConnectionState(int status, int serverIf,
94 boolean connected, String address) {
95 if (DBG) Log.d(TAG, "onServerConnectionState() - status=" + status
96 + " serverIf=" + serverIf + " device=" + address);
97 try {
98 mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status,
99 connected ? BluetoothProfile.STATE_CONNECTED :
100 BluetoothProfile.STATE_DISCONNECTED);
101 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700102 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800103 }
104 }
105
106 /**
107 * Service has been added
108 * @hide
109 */
110 public void onServiceAdded(int status, int srvcType,
111 int srvcInstId, ParcelUuid srvcId) {
112 UUID srvcUuid = srvcId.getUuid();
113 if (DBG) Log.d(TAG, "onServiceAdded() - service=" + srvcUuid
114 + "status=" + status);
115
116 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
117 if (service == null) return;
118
119 try {
120 mCallback.onServiceAdded((int)status, service);
121 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700122 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800123 }
124 }
125
126 /**
127 * Remote client characteristic read request.
128 * @hide
129 */
130 public void onCharacteristicReadRequest(String address, int transId,
131 int offset, boolean isLong, int srvcType, int srvcInstId,
132 ParcelUuid srvcId, int charInstId, ParcelUuid charId) {
133 UUID srvcUuid = srvcId.getUuid();
134 UUID charUuid = charId.getUuid();
135 if (DBG) Log.d(TAG, "onCharacteristicReadRequest() - "
136 + "service=" + srvcUuid + ", characteristic=" + charUuid);
137
138 BluetoothDevice device = mAdapter.getRemoteDevice(address);
139 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
140 if (service == null) return;
141
Matthew Xieddf7e472013-03-01 18:41:02 -0800142 BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800143 if (characteristic == null) return;
144
145 try {
146 mCallback.onCharacteristicReadRequest(device, transId, offset, characteristic);
147 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700148 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800149 }
150 }
151
152 /**
153 * Remote client descriptor read request.
154 * @hide
155 */
156 public void onDescriptorReadRequest(String address, int transId,
157 int offset, boolean isLong, int srvcType, int srvcInstId,
158 ParcelUuid srvcId, int charInstId, ParcelUuid charId,
159 ParcelUuid descrId) {
160 UUID srvcUuid = srvcId.getUuid();
161 UUID charUuid = charId.getUuid();
162 UUID descrUuid = descrId.getUuid();
163 if (DBG) Log.d(TAG, "onCharacteristicReadRequest() - "
164 + "service=" + srvcUuid + ", characteristic=" + charUuid
165 + "descriptor=" + descrUuid);
166
167 BluetoothDevice device = mAdapter.getRemoteDevice(address);
168 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
169 if (service == null) return;
170
171 BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
172 if (characteristic == null) return;
173
174 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descrUuid);
175 if (descriptor == null) return;
176
177 try {
178 mCallback.onDescriptorReadRequest(device, transId, offset, descriptor);
179 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700180 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800181 }
182 }
183
184 /**
185 * Remote client characteristic write request.
186 * @hide
187 */
188 public void onCharacteristicWriteRequest(String address, int transId,
189 int offset, int length, boolean isPrep, boolean needRsp,
190 int srvcType, int srvcInstId, ParcelUuid srvcId,
191 int charInstId, ParcelUuid charId, byte[] value) {
192 UUID srvcUuid = srvcId.getUuid();
193 UUID charUuid = charId.getUuid();
194 if (DBG) Log.d(TAG, "onCharacteristicWriteRequest() - "
195 + "service=" + srvcUuid + ", characteristic=" + charUuid);
196
197 BluetoothDevice device = mAdapter.getRemoteDevice(address);
198 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
199 if (service == null) return;
200
201 BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
202 if (characteristic == null) return;
203
204 try {
205 mCallback.onCharacteristicWriteRequest(device, transId, characteristic,
206 isPrep, needRsp, offset, value);
207 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700208 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800209 }
210
211 }
212
213 /**
214 * Remote client descriptor write request.
215 * @hide
216 */
217 public void onDescriptorWriteRequest(String address, int transId,
218 int offset, int length, boolean isPrep, boolean needRsp,
219 int srvcType, int srvcInstId, ParcelUuid srvcId,
220 int charInstId, ParcelUuid charId, ParcelUuid descrId,
221 byte[] value) {
222 UUID srvcUuid = srvcId.getUuid();
223 UUID charUuid = charId.getUuid();
224 UUID descrUuid = descrId.getUuid();
225 if (DBG) Log.d(TAG, "onDescriptorWriteRequest() - "
226 + "service=" + srvcUuid + ", characteristic=" + charUuid
227 + "descriptor=" + descrUuid);
228
229 BluetoothDevice device = mAdapter.getRemoteDevice(address);
230
231 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
232 if (service == null) return;
233
234 BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
235 if (characteristic == null) return;
236
237 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descrUuid);
238 if (descriptor == null) return;
239
240 try {
241 mCallback.onDescriptorWriteRequest(device, transId, descriptor,
242 isPrep, needRsp, offset, value);
243 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700244 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800245 }
246 }
247
248 /**
249 * Execute pending writes.
250 * @hide
251 */
252 public void onExecuteWrite(String address, int transId,
253 boolean execWrite) {
254 if (DBG) Log.d(TAG, "onExecuteWrite() - "
255 + "device=" + address + ", transId=" + transId
256 + "execWrite=" + execWrite);
257
258 BluetoothDevice device = mAdapter.getRemoteDevice(address);
259 if (device == null) return;
260
261 try {
262 mCallback.onExecuteWrite(device, transId, execWrite);
263 } catch (Exception ex) {
Mike Lockwood0998ff12013-05-13 14:04:12 -0700264 Log.w(TAG, "Unhandled exception in callback", ex);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800265 }
266 }
267 };
268
269 /**
270 * Create a BluetoothGattServer proxy object.
271 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800272 /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800273 mContext = context;
Matthew Xieddf7e472013-03-01 18:41:02 -0800274 mService = iGatt;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800275 mAdapter = BluetoothAdapter.getDefaultAdapter();
Matthew Xieddf7e472013-03-01 18:41:02 -0800276 mCallback = null;
277 mServerIf = 0;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800278 mServices = new ArrayList<BluetoothGattService>();
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800279 }
280
281 /**
Andre Eisenbach3b64f382013-04-05 09:34:11 -0700282 * Close this GATT server instance.
Matthew Xieb30f91e2013-05-29 10:19:06 -0700283 *
284 * Application should call this method as early as possible after it is done with
285 * this GATT server.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800286 */
Andre Eisenbach3b64f382013-04-05 09:34:11 -0700287 public void close() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800288 if (DBG) Log.d(TAG, "close()");
Matthew Xieddf7e472013-03-01 18:41:02 -0800289 unregisterCallback();
290 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800291
Matthew Xieddf7e472013-03-01 18:41:02 -0800292 /**
293 * Register an application callback to start using GattServer.
294 *
295 * <p>This is an asynchronous call. The callback is used to notify
296 * success or failure if the function returns true.
297 *
298 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
299 *
300 * @param callback GATT callback handler that will receive asynchronous
301 * callbacks.
302 * @return true, the callback will be called to notify success or failure,
303 * false on immediate error
304 */
305 /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
306 if (DBG) Log.d(TAG, "registerCallback()");
307 if (mService == null) {
308 Log.e(TAG, "GATT service not available");
309 return false;
310 }
311 UUID uuid = UUID.randomUUID();
312 if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800313
Matthew Xieddf7e472013-03-01 18:41:02 -0800314 synchronized(mServerIfLock) {
315 if (mCallback != null) {
316 Log.e(TAG, "App can register callback only once");
317 return false;
318 }
319
320 mCallback = callback;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800321 try {
Matthew Xieddf7e472013-03-01 18:41:02 -0800322 mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
323 } catch (RemoteException e) {
324 Log.e(TAG,"",e);
325 mCallback = null;
326 return false;
327 }
328
329 try {
330 mServerIfLock.wait(CALLBACK_REG_TIMEOUT);
331 } catch (InterruptedException e) {
332 Log.e(TAG, "" + e);
333 mCallback = null;
334 }
335
336 if (mServerIf == 0) {
337 mCallback = null;
338 return false;
339 } else {
340 return true;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800341 }
342 }
Matthew Xieddf7e472013-03-01 18:41:02 -0800343 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800344
Matthew Xieddf7e472013-03-01 18:41:02 -0800345 /**
346 * Unregister the current application and callbacks.
347 */
348 private void unregisterCallback() {
349 if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
350 if (mService == null || mServerIf == 0) return;
351
352 try {
353 mCallback = null;
354 mService.unregisterServer(mServerIf);
355 mServerIf = 0;
356 } catch (RemoteException e) {
357 Log.e(TAG,"",e);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800358 }
359 }
360
361 /**
362 * Returns a service by UUID, instance and type.
363 * @hide
364 */
365 /*package*/ BluetoothGattService getService(UUID uuid, int instanceId, int type) {
366 for(BluetoothGattService svc : mServices) {
367 if (svc.getType() == type &&
368 svc.getInstanceId() == instanceId &&
369 svc.getUuid().equals(uuid)) {
370 return svc;
371 }
372 }
373 return null;
374 }
375
376 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800377 * Initiate a connection to a Bluetooth GATT capable device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800378 *
379 * <p>The connection may not be established right away, but will be
380 * completed when the remote device is available. A
Andre Eisenbach3f366602013-03-08 18:42:24 -0800381 * {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800382 * invoked when the connection state changes as a result of this function.
383 *
384 * <p>The autoConnect paramter determines whether to actively connect to
385 * the remote device, or rather passively scan and finalize the connection
386 * when the remote device is in range/available. Generally, the first ever
387 * connection to a device should be direct (autoConnect set to false) and
388 * subsequent connections to known devices should be invoked with the
Matthew Xieddf7e472013-03-01 18:41:02 -0800389 * autoConnect parameter set to true.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800390 *
391 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
392 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800393 * @param autoConnect Whether to directly connect to the remote device (false)
394 * or to automatically connect as soon as the remote
395 * device becomes available (true).
396 * @return true, if the connection attempt was initiated successfully
397 */
398 public boolean connect(BluetoothDevice device, boolean autoConnect) {
Andre Eisenbach3f366602013-03-08 18:42:24 -0800399 if (DBG) Log.d(TAG, "connect() - device: " + device.getAddress() + ", auto: " + autoConnect);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800400 if (mService == null || mServerIf == 0) return false;
401
402 try {
403 mService.serverConnect(mServerIf, device.getAddress(),
404 autoConnect ? false : true); // autoConnect is inverse of "isDirect"
405 } catch (RemoteException e) {
406 Log.e(TAG,"",e);
407 return false;
408 }
409
410 return true;
411 }
412
413 /**
414 * Disconnects an established connection, or cancels a connection attempt
415 * currently in progress.
416 *
417 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
418 *
419 * @param device Remote device
420 */
421 public void cancelConnection(BluetoothDevice device) {
422 if (DBG) Log.d(TAG, "cancelConnection() - device: " + device.getAddress());
423 if (mService == null || mServerIf == 0) return;
424
425 try {
426 mService.serverDisconnect(mServerIf, device.getAddress());
427 } catch (RemoteException e) {
428 Log.e(TAG,"",e);
429 }
430 }
431
432 /**
433 * Send a response to a read or write request to a remote device.
434 *
435 * <p>This function must be invoked in when a remote read/write request
Matthew Xieddf7e472013-03-01 18:41:02 -0800436 * is received by one of these callback methods:
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800437 *
438 * <ul>
439 * <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest}
440 * <li>{@link BluetoothGattServerCallback#onCharacteristicWriteRequest}
441 * <li>{@link BluetoothGattServerCallback#onDescriptorReadRequest}
442 * <li>{@link BluetoothGattServerCallback#onDescriptorWriteRequest}
443 * </ul>
444 *
445 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
446 *
447 * @param device The remote device to send this response to
448 * @param requestId The ID of the request that was received with the callback
449 * @param status The status of the request to be sent to the remote devices
450 * @param offset Value offset for partial read/write response
451 * @param value The value of the attribute that was read/written (optional)
452 */
453 public boolean sendResponse(BluetoothDevice device, int requestId,
454 int status, int offset, byte[] value) {
455 if (DBG) Log.d(TAG, "sendResponse() - device: " + device.getAddress());
456 if (mService == null || mServerIf == 0) return false;
457
458 try {
459 mService.sendResponse(mServerIf, device.getAddress(), requestId,
460 status, offset, value);
461 } catch (RemoteException e) {
462 Log.e(TAG,"",e);
463 return false;
464 }
465 return true;
466 }
467
468 /**
469 * Send a notification or indication that a local characteristic has been
470 * updated.
471 *
472 * <p>A notification or indication is sent to the remote device to signal
473 * that the characteristic has been updated. This function should be invoked
474 * for every client that requests notifications/indications by writing
475 * to the "Client Configuration" descriptor for the given characteristic.
476 *
477 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
478 *
479 * @param device The remote device to receive the notification/indication
480 * @param characteristic The local characteristic that has been updated
481 * @param confirm true to request confirmation from the client (indication),
482 * false to send a notification
483 * @return true, if the notification has been triggered successfully
484 */
485 public boolean notifyCharacteristicChanged(BluetoothDevice device,
486 BluetoothGattCharacteristic characteristic, boolean confirm) {
487 if (DBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress());
488 if (mService == null || mServerIf == 0) return false;
489
490 BluetoothGattService service = characteristic.getService();
491 if (service == null) return false;
492
493 try {
494 mService.sendNotification(mServerIf, device.getAddress(),
495 service.getType(), service.getInstanceId(),
496 new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
497 new ParcelUuid(characteristic.getUuid()), confirm,
498 characteristic.getValue());
499 } catch (RemoteException e) {
500 Log.e(TAG,"",e);
501 return false;
502 }
503
504 return true;
505 }
506
507 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800508 * Add a service to the list of services to be hosted.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800509 *
510 * <p>Once a service has been addded to the the list, the service and it's
Matthew Xieddf7e472013-03-01 18:41:02 -0800511 * included characteristics will be provided by the local device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800512 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800513 * <p>If the local device has already exposed services when this function
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800514 * is called, a service update notification will be sent to all clients.
515 *
516 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
517 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800518 * @param service Service to be added to the list of services provided
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800519 * by this device.
520 * @return true, if the service has been added successfully
521 */
522 public boolean addService(BluetoothGattService service) {
523 if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid());
524 if (mService == null || mServerIf == 0) return false;
525
526 mServices.add(service);
527
528 try {
529 mService.beginServiceDeclaration(mServerIf, service.getType(),
530 service.getInstanceId(), service.getHandles(),
Wei Wang18c76932013-10-29 21:05:37 -0700531 new ParcelUuid(service.getUuid()), service.isAdvertisePreferred());
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800532
533 List<BluetoothGattService> includedServices = service.getIncludedServices();
534 for (BluetoothGattService includedService : includedServices) {
535 mService.addIncludedService(mServerIf,
536 includedService.getType(),
537 includedService.getInstanceId(),
538 new ParcelUuid(includedService.getUuid()));
539 }
540
541 List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
542 for (BluetoothGattCharacteristic characteristic : characteristics) {
543 int permission = ((characteristic.getKeySize() - 7) << 12)
544 + characteristic.getPermissions();
545 mService.addCharacteristic(mServerIf,
546 new ParcelUuid(characteristic.getUuid()),
547 characteristic.getProperties(), permission);
548
549 List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
550 for (BluetoothGattDescriptor descriptor: descriptors) {
Andre Eisenbach6f0ed122013-04-03 14:26:43 -0700551 permission = ((characteristic.getKeySize() - 7) << 12)
552 + descriptor.getPermissions();
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800553 mService.addDescriptor(mServerIf,
Andre Eisenbach6f0ed122013-04-03 14:26:43 -0700554 new ParcelUuid(descriptor.getUuid()), permission);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800555 }
556 }
557
558 mService.endServiceDeclaration(mServerIf);
559 } catch (RemoteException e) {
560 Log.e(TAG,"",e);
561 return false;
562 }
563
564 return true;
565 }
566
567 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800568 * Removes a service from the list of services to be provided.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800569 *
570 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
571 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800572 * @param service Service to be removed.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800573 * @return true, if the service has been removed
574 */
575 public boolean removeService(BluetoothGattService service) {
576 if (DBG) Log.d(TAG, "removeService() - service: " + service.getUuid());
577 if (mService == null || mServerIf == 0) return false;
578
579 BluetoothGattService intService = getService(service.getUuid(),
580 service.getInstanceId(), service.getType());
581 if (intService == null) return false;
582
583 try {
584 mService.removeService(mServerIf, service.getType(),
585 service.getInstanceId(), new ParcelUuid(service.getUuid()));
586 mServices.remove(intService);
587 } catch (RemoteException e) {
588 Log.e(TAG,"",e);
589 return false;
590 }
591
592 return true;
593 }
594
595 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800596 * Remove all services from the list of provided services.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800597 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
598 */
599 public void clearServices() {
600 if (DBG) Log.d(TAG, "clearServices()");
601 if (mService == null || mServerIf == 0) return;
602
603 try {
604 mService.clearServices(mServerIf);
605 mServices.clear();
606 } catch (RemoteException e) {
607 Log.e(TAG,"",e);
608 }
609 }
610
611 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800612 * Returns a list of GATT services offered by this device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800613 *
614 * <p>An application must call {@link #addService} to add a serice to the
615 * list of services offered by this device.
616 *
617 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
618 *
619 * @return List of services. Returns an empty list
620 * if no services have been added yet.
621 */
622 public List<BluetoothGattService> getServices() {
623 return mServices;
624 }
625
626 /**
627 * Returns a {@link BluetoothGattService} from the list of services offered
628 * by this device.
629 *
630 * <p>If multiple instances of the same service (as identified by UUID)
631 * exist, the first instance of the service is returned.
632 *
633 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
634 *
635 * @param uuid UUID of the requested service
636 * @return BluetoothGattService if supported, or null if the requested
637 * service is not offered by this device.
638 */
639 public BluetoothGattService getService(UUID uuid) {
640 for (BluetoothGattService service : mServices) {
641 if (service.getUuid().equals(uuid)) {
642 return service;
643 }
644 }
645
646 return null;
647 }
648
Matthew Xieddf7e472013-03-01 18:41:02 -0800649
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800650 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800651 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
652 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800653 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800654 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800655 */
656 @Override
657 public int getConnectionState(BluetoothDevice device) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800658 throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800659 }
660
661 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800662 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
663 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800664 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800665 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800666 */
667 @Override
668 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xieddf7e472013-03-01 18:41:02 -0800669 throw new UnsupportedOperationException
670 ("Use BluetoothManager#getConnectedDevices instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800671 }
672
673 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800674 * Not supported - please use
675 * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
676 * with {@link BluetoothProfile#GATT} as first argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800677 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800678 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800679 */
680 @Override
681 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800682 throw new UnsupportedOperationException
683 ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800684 }
685}