blob: d7f150b319100f9a9beb44abc9023a9ac796d3f3 [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;
22import android.bluetooth.BluetoothProfile.ServiceListener;
23import android.bluetooth.IBluetoothManager;
24import android.bluetooth.IBluetoothStateChangeCallback;
25
26import android.content.ComponentName;
27import android.content.Context;
28import android.content.Intent;
29import android.content.ServiceConnection;
30import android.os.IBinder;
31import android.os.ParcelUuid;
32import android.os.RemoteException;
33import android.os.ServiceManager;
34import android.util.Log;
35
36import java.util.ArrayList;
37import java.util.List;
38import java.util.UUID;
39
40/**
Matthew Xieddf7e472013-03-01 18:41:02 -080041 * Public API for the Bluetooth GATT Profile server role.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080042 *
Matthew Xieddf7e472013-03-01 18:41:02 -080043 * <p>This class provides Bluetooth GATT server role functionality,
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080044 * allowing applications to create and advertise Bluetooth Smart services
45 * and characteristics.
46 *
47 * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
48 * via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
49 * BluetoothGatt proxy object.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080050 */
51public final class BluetoothGattServer implements BluetoothProfile {
52 private static final String TAG = "BluetoothGattServer";
53 private static final boolean DBG = true;
54
Matthew Xieddf7e472013-03-01 18:41:02 -080055 private final Context mContext;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080056 private BluetoothAdapter mAdapter;
57 private IBluetoothGatt mService;
58 private BluetoothGattServerCallback mCallback;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080059
Matthew Xieddf7e472013-03-01 18:41:02 -080060 private Object mServerIfLock = new Object();
61 private int mServerIf;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080062 private List<BluetoothGattService> mServices;
63
Matthew Xieddf7e472013-03-01 18:41:02 -080064 private static final int CALLBACK_REG_TIMEOUT = 10000;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080065
66 /**
67 * Bluetooth GATT interface callbacks
68 */
69 private final IBluetoothGattServerCallback mBluetoothGattServerCallback =
70 new IBluetoothGattServerCallback.Stub() {
71 /**
72 * Application interface registered - app is ready to go
73 * @hide
74 */
75 public void onServerRegistered(int status, int serverIf) {
76 if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status
77 + " serverIf=" + serverIf);
Matthew Xieddf7e472013-03-01 18:41:02 -080078 synchronized(mServerIfLock) {
79 if (mCallback != null) {
80 mServerIf = serverIf;
81 mServerIfLock.notify();
82 } else {
83 // registration timeout
84 Log.e(TAG, "onServerRegistered: mCallback is null");
85 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080086 }
87 }
88
89 /**
90 * Callback reporting an LE scan result.
91 * @hide
92 */
93 public void onScanResult(String address, int rssi, byte[] advData) {
94 if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
Matthew Xieddf7e472013-03-01 18:41:02 -080095 // no op
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -080096 }
97
98 /**
99 * Server connection state changed
100 * @hide
101 */
102 public void onServerConnectionState(int status, int serverIf,
103 boolean connected, String address) {
104 if (DBG) Log.d(TAG, "onServerConnectionState() - status=" + status
105 + " serverIf=" + serverIf + " device=" + address);
106 try {
107 mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status,
108 connected ? BluetoothProfile.STATE_CONNECTED :
109 BluetoothProfile.STATE_DISCONNECTED);
110 } catch (Exception ex) {
111 Log.w(TAG, "Unhandled exception: " + ex);
112 }
113 }
114
115 /**
116 * Service has been added
117 * @hide
118 */
119 public void onServiceAdded(int status, int srvcType,
120 int srvcInstId, ParcelUuid srvcId) {
121 UUID srvcUuid = srvcId.getUuid();
122 if (DBG) Log.d(TAG, "onServiceAdded() - service=" + srvcUuid
123 + "status=" + status);
124
125 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
126 if (service == null) return;
127
128 try {
129 mCallback.onServiceAdded((int)status, service);
130 } catch (Exception ex) {
131 Log.w(TAG, "Unhandled exception: " + ex);
132 }
133 }
134
135 /**
136 * Remote client characteristic read request.
137 * @hide
138 */
139 public void onCharacteristicReadRequest(String address, int transId,
140 int offset, boolean isLong, int srvcType, int srvcInstId,
141 ParcelUuid srvcId, int charInstId, ParcelUuid charId) {
142 UUID srvcUuid = srvcId.getUuid();
143 UUID charUuid = charId.getUuid();
144 if (DBG) Log.d(TAG, "onCharacteristicReadRequest() - "
145 + "service=" + srvcUuid + ", characteristic=" + charUuid);
146
147 BluetoothDevice device = mAdapter.getRemoteDevice(address);
148 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
149 if (service == null) return;
150
Matthew Xieddf7e472013-03-01 18:41:02 -0800151 BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800152 if (characteristic == null) return;
153
154 try {
155 mCallback.onCharacteristicReadRequest(device, transId, offset, characteristic);
156 } catch (Exception ex) {
157 Log.w(TAG, "Unhandled exception: " + ex);
158 }
159 }
160
161 /**
162 * Remote client descriptor read request.
163 * @hide
164 */
165 public void onDescriptorReadRequest(String address, int transId,
166 int offset, boolean isLong, int srvcType, int srvcInstId,
167 ParcelUuid srvcId, int charInstId, ParcelUuid charId,
168 ParcelUuid descrId) {
169 UUID srvcUuid = srvcId.getUuid();
170 UUID charUuid = charId.getUuid();
171 UUID descrUuid = descrId.getUuid();
172 if (DBG) Log.d(TAG, "onCharacteristicReadRequest() - "
173 + "service=" + srvcUuid + ", characteristic=" + charUuid
174 + "descriptor=" + descrUuid);
175
176 BluetoothDevice device = mAdapter.getRemoteDevice(address);
177 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
178 if (service == null) return;
179
180 BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
181 if (characteristic == null) return;
182
183 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descrUuid);
184 if (descriptor == null) return;
185
186 try {
187 mCallback.onDescriptorReadRequest(device, transId, offset, descriptor);
188 } catch (Exception ex) {
189 Log.w(TAG, "Unhandled exception: " + ex);
190 }
191 }
192
193 /**
194 * Remote client characteristic write request.
195 * @hide
196 */
197 public void onCharacteristicWriteRequest(String address, int transId,
198 int offset, int length, boolean isPrep, boolean needRsp,
199 int srvcType, int srvcInstId, ParcelUuid srvcId,
200 int charInstId, ParcelUuid charId, byte[] value) {
201 UUID srvcUuid = srvcId.getUuid();
202 UUID charUuid = charId.getUuid();
203 if (DBG) Log.d(TAG, "onCharacteristicWriteRequest() - "
204 + "service=" + srvcUuid + ", characteristic=" + charUuid);
205
206 BluetoothDevice device = mAdapter.getRemoteDevice(address);
207 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
208 if (service == null) return;
209
210 BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
211 if (characteristic == null) return;
212
213 try {
214 mCallback.onCharacteristicWriteRequest(device, transId, characteristic,
215 isPrep, needRsp, offset, value);
216 } catch (Exception ex) {
217 Log.w(TAG, "Unhandled exception: " + ex);
218 }
219
220 }
221
222 /**
223 * Remote client descriptor write request.
224 * @hide
225 */
226 public void onDescriptorWriteRequest(String address, int transId,
227 int offset, int length, boolean isPrep, boolean needRsp,
228 int srvcType, int srvcInstId, ParcelUuid srvcId,
229 int charInstId, ParcelUuid charId, ParcelUuid descrId,
230 byte[] value) {
231 UUID srvcUuid = srvcId.getUuid();
232 UUID charUuid = charId.getUuid();
233 UUID descrUuid = descrId.getUuid();
234 if (DBG) Log.d(TAG, "onDescriptorWriteRequest() - "
235 + "service=" + srvcUuid + ", characteristic=" + charUuid
236 + "descriptor=" + descrUuid);
237
238 BluetoothDevice device = mAdapter.getRemoteDevice(address);
239
240 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
241 if (service == null) return;
242
243 BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
244 if (characteristic == null) return;
245
246 BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descrUuid);
247 if (descriptor == null) return;
248
249 try {
250 mCallback.onDescriptorWriteRequest(device, transId, descriptor,
251 isPrep, needRsp, offset, value);
252 } catch (Exception ex) {
253 Log.w(TAG, "Unhandled exception: " + ex);
254 }
255 }
256
257 /**
258 * Execute pending writes.
259 * @hide
260 */
261 public void onExecuteWrite(String address, int transId,
262 boolean execWrite) {
263 if (DBG) Log.d(TAG, "onExecuteWrite() - "
264 + "device=" + address + ", transId=" + transId
265 + "execWrite=" + execWrite);
266
267 BluetoothDevice device = mAdapter.getRemoteDevice(address);
268 if (device == null) return;
269
270 try {
271 mCallback.onExecuteWrite(device, transId, execWrite);
272 } catch (Exception ex) {
273 Log.w(TAG, "Unhandled exception: " + ex);
274 }
275 }
276 };
277
278 /**
279 * Create a BluetoothGattServer proxy object.
280 */
Matthew Xieddf7e472013-03-01 18:41:02 -0800281 /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800282 mContext = context;
Matthew Xieddf7e472013-03-01 18:41:02 -0800283 mService = iGatt;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800284 mAdapter = BluetoothAdapter.getDefaultAdapter();
Matthew Xieddf7e472013-03-01 18:41:02 -0800285 mCallback = null;
286 mServerIf = 0;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800287 mServices = new ArrayList<BluetoothGattService>();
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800288 }
289
290 /**
Andre Eisenbach3b64f382013-04-05 09:34:11 -0700291 * Close this GATT server instance.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800292 */
Andre Eisenbach3b64f382013-04-05 09:34:11 -0700293 public void close() {
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800294 if (DBG) Log.d(TAG, "close()");
Matthew Xieddf7e472013-03-01 18:41:02 -0800295 unregisterCallback();
296 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800297
Matthew Xieddf7e472013-03-01 18:41:02 -0800298 /**
299 * Register an application callback to start using GattServer.
300 *
301 * <p>This is an asynchronous call. The callback is used to notify
302 * success or failure if the function returns true.
303 *
304 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
305 *
306 * @param callback GATT callback handler that will receive asynchronous
307 * callbacks.
308 * @return true, the callback will be called to notify success or failure,
309 * false on immediate error
310 */
311 /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
312 if (DBG) Log.d(TAG, "registerCallback()");
313 if (mService == null) {
314 Log.e(TAG, "GATT service not available");
315 return false;
316 }
317 UUID uuid = UUID.randomUUID();
318 if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800319
Matthew Xieddf7e472013-03-01 18:41:02 -0800320 synchronized(mServerIfLock) {
321 if (mCallback != null) {
322 Log.e(TAG, "App can register callback only once");
323 return false;
324 }
325
326 mCallback = callback;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800327 try {
Matthew Xieddf7e472013-03-01 18:41:02 -0800328 mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
329 } catch (RemoteException e) {
330 Log.e(TAG,"",e);
331 mCallback = null;
332 return false;
333 }
334
335 try {
336 mServerIfLock.wait(CALLBACK_REG_TIMEOUT);
337 } catch (InterruptedException e) {
338 Log.e(TAG, "" + e);
339 mCallback = null;
340 }
341
342 if (mServerIf == 0) {
343 mCallback = null;
344 return false;
345 } else {
346 return true;
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800347 }
348 }
Matthew Xieddf7e472013-03-01 18:41:02 -0800349 }
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800350
Matthew Xieddf7e472013-03-01 18:41:02 -0800351 /**
352 * Unregister the current application and callbacks.
353 */
354 private void unregisterCallback() {
355 if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
356 if (mService == null || mServerIf == 0) return;
357
358 try {
359 mCallback = null;
360 mService.unregisterServer(mServerIf);
361 mServerIf = 0;
362 } catch (RemoteException e) {
363 Log.e(TAG,"",e);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800364 }
365 }
366
367 /**
368 * Returns a service by UUID, instance and type.
369 * @hide
370 */
371 /*package*/ BluetoothGattService getService(UUID uuid, int instanceId, int type) {
372 for(BluetoothGattService svc : mServices) {
373 if (svc.getType() == type &&
374 svc.getInstanceId() == instanceId &&
375 svc.getUuid().equals(uuid)) {
376 return svc;
377 }
378 }
379 return null;
380 }
381
382 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800383 * Initiate a connection to a Bluetooth GATT capable device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800384 *
385 * <p>The connection may not be established right away, but will be
386 * completed when the remote device is available. A
Andre Eisenbach3f366602013-03-08 18:42:24 -0800387 * {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800388 * invoked when the connection state changes as a result of this function.
389 *
390 * <p>The autoConnect paramter determines whether to actively connect to
391 * the remote device, or rather passively scan and finalize the connection
392 * when the remote device is in range/available. Generally, the first ever
393 * connection to a device should be direct (autoConnect set to false) and
394 * subsequent connections to known devices should be invoked with the
Matthew Xieddf7e472013-03-01 18:41:02 -0800395 * autoConnect parameter set to true.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800396 *
397 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
398 *
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800399 * @param autoConnect Whether to directly connect to the remote device (false)
400 * or to automatically connect as soon as the remote
401 * device becomes available (true).
402 * @return true, if the connection attempt was initiated successfully
403 */
404 public boolean connect(BluetoothDevice device, boolean autoConnect) {
Andre Eisenbach3f366602013-03-08 18:42:24 -0800405 if (DBG) Log.d(TAG, "connect() - device: " + device.getAddress() + ", auto: " + autoConnect);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800406 if (mService == null || mServerIf == 0) return false;
407
408 try {
409 mService.serverConnect(mServerIf, device.getAddress(),
410 autoConnect ? false : true); // autoConnect is inverse of "isDirect"
411 } catch (RemoteException e) {
412 Log.e(TAG,"",e);
413 return false;
414 }
415
416 return true;
417 }
418
419 /**
420 * Disconnects an established connection, or cancels a connection attempt
421 * currently in progress.
422 *
423 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
424 *
425 * @param device Remote device
426 */
427 public void cancelConnection(BluetoothDevice device) {
428 if (DBG) Log.d(TAG, "cancelConnection() - device: " + device.getAddress());
429 if (mService == null || mServerIf == 0) return;
430
431 try {
432 mService.serverDisconnect(mServerIf, device.getAddress());
433 } catch (RemoteException e) {
434 Log.e(TAG,"",e);
435 }
436 }
437
438 /**
439 * Send a response to a read or write request to a remote device.
440 *
441 * <p>This function must be invoked in when a remote read/write request
Matthew Xieddf7e472013-03-01 18:41:02 -0800442 * is received by one of these callback methods:
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800443 *
444 * <ul>
445 * <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest}
446 * <li>{@link BluetoothGattServerCallback#onCharacteristicWriteRequest}
447 * <li>{@link BluetoothGattServerCallback#onDescriptorReadRequest}
448 * <li>{@link BluetoothGattServerCallback#onDescriptorWriteRequest}
449 * </ul>
450 *
451 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
452 *
453 * @param device The remote device to send this response to
454 * @param requestId The ID of the request that was received with the callback
455 * @param status The status of the request to be sent to the remote devices
456 * @param offset Value offset for partial read/write response
457 * @param value The value of the attribute that was read/written (optional)
458 */
459 public boolean sendResponse(BluetoothDevice device, int requestId,
460 int status, int offset, byte[] value) {
461 if (DBG) Log.d(TAG, "sendResponse() - device: " + device.getAddress());
462 if (mService == null || mServerIf == 0) return false;
463
464 try {
465 mService.sendResponse(mServerIf, device.getAddress(), requestId,
466 status, offset, value);
467 } catch (RemoteException e) {
468 Log.e(TAG,"",e);
469 return false;
470 }
471 return true;
472 }
473
474 /**
475 * Send a notification or indication that a local characteristic has been
476 * updated.
477 *
478 * <p>A notification or indication is sent to the remote device to signal
479 * that the characteristic has been updated. This function should be invoked
480 * for every client that requests notifications/indications by writing
481 * to the "Client Configuration" descriptor for the given characteristic.
482 *
483 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
484 *
485 * @param device The remote device to receive the notification/indication
486 * @param characteristic The local characteristic that has been updated
487 * @param confirm true to request confirmation from the client (indication),
488 * false to send a notification
489 * @return true, if the notification has been triggered successfully
490 */
491 public boolean notifyCharacteristicChanged(BluetoothDevice device,
492 BluetoothGattCharacteristic characteristic, boolean confirm) {
493 if (DBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress());
494 if (mService == null || mServerIf == 0) return false;
495
496 BluetoothGattService service = characteristic.getService();
497 if (service == null) return false;
498
499 try {
500 mService.sendNotification(mServerIf, device.getAddress(),
501 service.getType(), service.getInstanceId(),
502 new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
503 new ParcelUuid(characteristic.getUuid()), confirm,
504 characteristic.getValue());
505 } catch (RemoteException e) {
506 Log.e(TAG,"",e);
507 return false;
508 }
509
510 return true;
511 }
512
513 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800514 * Add a service to the list of services to be hosted.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800515 *
516 * <p>Once a service has been addded to the the list, the service and it's
Matthew Xieddf7e472013-03-01 18:41:02 -0800517 * included characteristics will be provided by the local device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800518 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800519 * <p>If the local device has already exposed services when this function
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800520 * is called, a service update notification will be sent to all clients.
521 *
522 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
523 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800524 * @param service Service to be added to the list of services provided
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800525 * by this device.
526 * @return true, if the service has been added successfully
527 */
528 public boolean addService(BluetoothGattService service) {
529 if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid());
530 if (mService == null || mServerIf == 0) return false;
531
532 mServices.add(service);
533
534 try {
535 mService.beginServiceDeclaration(mServerIf, service.getType(),
536 service.getInstanceId(), service.getHandles(),
537 new ParcelUuid(service.getUuid()));
538
539 List<BluetoothGattService> includedServices = service.getIncludedServices();
540 for (BluetoothGattService includedService : includedServices) {
541 mService.addIncludedService(mServerIf,
542 includedService.getType(),
543 includedService.getInstanceId(),
544 new ParcelUuid(includedService.getUuid()));
545 }
546
547 List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
548 for (BluetoothGattCharacteristic characteristic : characteristics) {
549 int permission = ((characteristic.getKeySize() - 7) << 12)
550 + characteristic.getPermissions();
551 mService.addCharacteristic(mServerIf,
552 new ParcelUuid(characteristic.getUuid()),
553 characteristic.getProperties(), permission);
554
555 List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
556 for (BluetoothGattDescriptor descriptor: descriptors) {
Andre Eisenbach6f0ed122013-04-03 14:26:43 -0700557 permission = ((characteristic.getKeySize() - 7) << 12)
558 + descriptor.getPermissions();
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800559 mService.addDescriptor(mServerIf,
Andre Eisenbach6f0ed122013-04-03 14:26:43 -0700560 new ParcelUuid(descriptor.getUuid()), permission);
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800561 }
562 }
563
564 mService.endServiceDeclaration(mServerIf);
565 } catch (RemoteException e) {
566 Log.e(TAG,"",e);
567 return false;
568 }
569
570 return true;
571 }
572
573 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800574 * Removes a service from the list of services to be provided.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800575 *
576 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
577 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800578 * @param service Service to be removed.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800579 * @return true, if the service has been removed
580 */
581 public boolean removeService(BluetoothGattService service) {
582 if (DBG) Log.d(TAG, "removeService() - service: " + service.getUuid());
583 if (mService == null || mServerIf == 0) return false;
584
585 BluetoothGattService intService = getService(service.getUuid(),
586 service.getInstanceId(), service.getType());
587 if (intService == null) return false;
588
589 try {
590 mService.removeService(mServerIf, service.getType(),
591 service.getInstanceId(), new ParcelUuid(service.getUuid()));
592 mServices.remove(intService);
593 } catch (RemoteException e) {
594 Log.e(TAG,"",e);
595 return false;
596 }
597
598 return true;
599 }
600
601 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800602 * Remove all services from the list of provided services.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800603 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
604 */
605 public void clearServices() {
606 if (DBG) Log.d(TAG, "clearServices()");
607 if (mService == null || mServerIf == 0) return;
608
609 try {
610 mService.clearServices(mServerIf);
611 mServices.clear();
612 } catch (RemoteException e) {
613 Log.e(TAG,"",e);
614 }
615 }
616
617 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800618 * Returns a list of GATT services offered by this device.
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800619 *
620 * <p>An application must call {@link #addService} to add a serice to the
621 * list of services offered by this device.
622 *
623 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
624 *
625 * @return List of services. Returns an empty list
626 * if no services have been added yet.
627 */
628 public List<BluetoothGattService> getServices() {
629 return mServices;
630 }
631
632 /**
633 * Returns a {@link BluetoothGattService} from the list of services offered
634 * by this device.
635 *
636 * <p>If multiple instances of the same service (as identified by UUID)
637 * exist, the first instance of the service is returned.
638 *
639 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
640 *
641 * @param uuid UUID of the requested service
642 * @return BluetoothGattService if supported, or null if the requested
643 * service is not offered by this device.
644 */
645 public BluetoothGattService getService(UUID uuid) {
646 for (BluetoothGattService service : mServices) {
647 if (service.getUuid().equals(uuid)) {
648 return service;
649 }
650 }
651
652 return null;
653 }
654
Matthew Xieddf7e472013-03-01 18:41:02 -0800655
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800656 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800657 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
658 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800659 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800660 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800661 */
662 @Override
663 public int getConnectionState(BluetoothDevice device) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800664 throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800665 }
666
667 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800668 * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
669 * with {@link BluetoothProfile#GATT} as argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800670 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800671 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800672 */
673 @Override
674 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xieddf7e472013-03-01 18:41:02 -0800675 throw new UnsupportedOperationException
676 ("Use BluetoothManager#getConnectedDevices instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800677 }
678
679 /**
Matthew Xieddf7e472013-03-01 18:41:02 -0800680 * Not supported - please use
681 * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
682 * with {@link BluetoothProfile#GATT} as first argument
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800683 *
Matthew Xieddf7e472013-03-01 18:41:02 -0800684 * @throws UnsupportedOperationException
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800685 */
686 @Override
687 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800688 throw new UnsupportedOperationException
689 ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
Ganesh Ganapathi Batta99081122013-02-05 15:28:33 -0800690 }
691}