GattService.java revision dbaf9cd41555de7e6101f368ac348bbeb2094809
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 17package com.android.bluetooth.gatt; 18 19import android.app.Service; 20import android.bluetooth.BluetoothAdapter; 21import android.bluetooth.BluetoothDevice; 22import android.bluetooth.BluetoothProfile; 23import android.bluetooth.IBluetoothGatt; 24import android.bluetooth.IBluetoothGattCallback; 25import android.bluetooth.IBluetoothGattServerCallback; 26import android.content.Intent; 27import android.os.IBinder; 28import android.os.IBinder.DeathRecipient; 29import android.os.ParcelUuid; 30import android.os.RemoteException; 31import android.util.Log; 32 33import java.util.ArrayList; 34import java.util.HashMap; 35import java.util.HashSet; 36import java.util.Iterator; 37import java.util.List; 38import java.util.Map; 39import java.util.Set; 40import java.util.UUID; 41 42import com.android.bluetooth.btservice.ProfileService; 43import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; 44 45/** 46 * Provides Bluetooth Gatt profile, as a service in 47 * the Bluetooth application. 48 * @hide 49 */ 50public class GattService extends ProfileService { 51 private static final boolean DBG = GattServiceConfig.DBG; 52 private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService"; 53 BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter(); 54 55 /** 56 * Search queue to serialize remote onbject inspection. 57 */ 58 SearchQueue mSearchQueue = new SearchQueue(); 59 60 /** 61 * List of our registered clients. 62 */ 63 64 class ClientMap extends ContextMap<IBluetoothGattCallback> {} 65 ClientMap mClientMap = new ClientMap(); 66 67 /** 68 * List of our registered server apps. 69 */ 70 class ServerMap extends ContextMap<IBluetoothGattServerCallback> {} 71 ServerMap mServerMap = new ServerMap(); 72 73 /** 74 * Server handle map. 75 */ 76 HandleMap mHandleMap = new HandleMap(); 77 78 /** 79 * Pending service declaration queue 80 */ 81 private List<ServiceDeclaration> mServiceDeclarations = new ArrayList<ServiceDeclaration>(); 82 83 private ServiceDeclaration addDeclaration() { 84 synchronized (mServiceDeclarations) { 85 mServiceDeclarations.add(new ServiceDeclaration()); 86 } 87 return getActiveDeclaration(); 88 } 89 90 private ServiceDeclaration getActiveDeclaration() { 91 synchronized (mServiceDeclarations) { 92 if (mServiceDeclarations.size() > 0) 93 return mServiceDeclarations.get(mServiceDeclarations.size() - 1); 94 } 95 return null; 96 } 97 98 private ServiceDeclaration getPendingDeclaration() { 99 synchronized (mServiceDeclarations) { 100 if (mServiceDeclarations.size() > 0) 101 return mServiceDeclarations.get(0); 102 } 103 return null; 104 } 105 106 private void removePendingDeclaration() { 107 synchronized (mServiceDeclarations) { 108 if (mServiceDeclarations.size() > 0) 109 mServiceDeclarations.remove(0); 110 } 111 } 112 113 /** 114 * List of clients intereste in scan results. 115 */ 116 private List<ScanClient> mScanQueue = new ArrayList<ScanClient>(); 117 118 private ScanClient getScanClient(int appIf, boolean isServer) { 119 for(ScanClient client : mScanQueue) { 120 if (client.appIf == appIf && client.isServer == isServer) { 121 return client; 122 } 123 } 124 return null; 125 } 126 127 private void removeScanClient(int appIf, boolean isServer) { 128 for(ScanClient client : mScanQueue) { 129 if (client.appIf == appIf && client.isServer == isServer) { 130 mScanQueue.remove(client); 131 break; 132 } 133 } 134 } 135 136 /** 137 * Reliable write queue 138 */ 139 private Set<String> mReliableQueue = new HashSet<String>(); 140 141 static { 142 classInitNative(); 143 } 144 145 protected String getName() { 146 return TAG; 147 } 148 149 protected IProfileServiceBinder initBinder() { 150 return new BluetoothGattBinder(this); 151 } 152 153 protected boolean start() { 154 if (DBG) Log.d(TAG, "start()"); 155 initializeNative(); 156 return true; 157 } 158 159 protected boolean stop() { 160 if (DBG) Log.d(TAG, "stop()"); 161 mClientMap.clear(); 162 mServerMap.clear(); 163 mSearchQueue.clear(); 164 mScanQueue.clear(); 165 mHandleMap.clear(); 166 mServiceDeclarations.clear(); 167 mReliableQueue.clear(); 168 return true; 169 } 170 171 protected boolean cleanup() { 172 if (DBG) Log.d(TAG, "cleanup()"); 173 cleanupNative(); 174 return true; 175 } 176 177 @Override 178 public int onStartCommand(Intent intent, int flags, int startId) { 179 if (GattDebugUtils.handleDebugAction(this, intent)) { 180 return Service.START_NOT_STICKY; 181 } 182 return super.onStartCommand(intent, flags, startId); 183 } 184 185 /** 186 * DeathReceipient handlers used to unregister applications that 187 * disconnect ungracefully (ie. crash or forced close). 188 */ 189 190 class ClientDeathRecipient implements IBinder.DeathRecipient { 191 int mAppIf; 192 193 public ClientDeathRecipient(int appIf) { 194 mAppIf = appIf; 195 } 196 197 public void binderDied() { 198 if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!"); 199 unregisterClient(mAppIf); 200 } 201 } 202 203 class ServerDeathRecipient implements IBinder.DeathRecipient { 204 int mAppIf; 205 206 public ServerDeathRecipient(int appIf) { 207 mAppIf = appIf; 208 } 209 210 public void binderDied() { 211 if (DBG) Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!"); 212 unregisterServer(mAppIf); 213 } 214 } 215 216 /** 217 * Handlers for incoming service calls 218 */ 219 private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder { 220 private GattService mService; 221 222 public BluetoothGattBinder(GattService svc) { 223 mService = svc; 224 } 225 226 public boolean cleanup() { 227 mService = null; 228 return true; 229 } 230 231 private GattService getService() { 232 if (mService != null && mService.isAvailable()) return mService; 233 Log.e(TAG, "getService() - Service requested, but not available!"); 234 return null; 235 } 236 237 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 238 GattService service = getService(); 239 if (service == null) return new ArrayList<BluetoothDevice>(); 240 return service.getDevicesMatchingConnectionStates(states); 241 } 242 243 public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) { 244 GattService service = getService(); 245 if (service == null) return; 246 service.registerClient(uuid.getUuid(), callback); 247 } 248 249 public void unregisterClient(int clientIf) { 250 GattService service = getService(); 251 if (service == null) return; 252 service.unregisterClient(clientIf); 253 } 254 255 public void startScan(int appIf, boolean isServer) { 256 GattService service = getService(); 257 if (service == null) return; 258 service.startScan(appIf, isServer); 259 } 260 261 public void startScanWithUuids(int appIf, boolean isServer, ParcelUuid[] ids) { 262 GattService service = getService(); 263 if (service == null) return; 264 UUID[] uuids = new UUID[ids.length]; 265 for(int i = 0; i != ids.length; ++i) { 266 uuids[i] = ids[i].getUuid(); 267 } 268 service.startScanWithUuids(appIf, isServer, uuids); 269 } 270 271 public void stopScan(int appIf, boolean isServer) { 272 GattService service = getService(); 273 if (service == null) return; 274 service.stopScan(appIf, isServer); 275 } 276 277 public void clientConnect(int clientIf, String address, boolean isDirect) { 278 GattService service = getService(); 279 if (service == null) return; 280 service.clientConnect(clientIf, address, isDirect); 281 } 282 283 public void clientDisconnect(int clientIf, String address) { 284 GattService service = getService(); 285 if (service == null) return; 286 service.clientDisconnect(clientIf, address); 287 } 288 289 public void refreshDevice(int clientIf, String address) { 290 GattService service = getService(); 291 if (service == null) return; 292 service.refreshDevice(clientIf, address); 293 } 294 295 public void discoverServices(int clientIf, String address) { 296 GattService service = getService(); 297 if (service == null) return; 298 service.discoverServices(clientIf, address); 299 } 300 301 public void readCharacteristic(int clientIf, String address, int srvcType, 302 int srvcInstanceId, ParcelUuid srvcId, 303 int charInstanceId, ParcelUuid charId, 304 int authReq) { 305 GattService service = getService(); 306 if (service == null) return; 307 service.readCharacteristic(clientIf, address, srvcType, srvcInstanceId, 308 srvcId.getUuid(), charInstanceId, 309 charId.getUuid(), authReq); 310 } 311 312 public void writeCharacteristic(int clientIf, String address, int srvcType, 313 int srvcInstanceId, ParcelUuid srvcId, 314 int charInstanceId, ParcelUuid charId, 315 int writeType, int authReq, byte[] value) { 316 GattService service = getService(); 317 if (service == null) return; 318 service.writeCharacteristic(clientIf, address, srvcType, srvcInstanceId, 319 srvcId.getUuid(), charInstanceId, 320 charId.getUuid(), writeType, authReq, 321 value); 322 } 323 324 public void readDescriptor(int clientIf, String address, int srvcType, 325 int srvcInstanceId, ParcelUuid srvcId, 326 int charInstanceId, ParcelUuid charId, 327 ParcelUuid descrId, int authReq) { 328 GattService service = getService(); 329 if (service == null) return; 330 service.readDescriptor(clientIf, address, srvcType, srvcInstanceId, 331 srvcId.getUuid(), charInstanceId, 332 charId.getUuid(), descrId.getUuid(), 333 authReq); 334 } 335 336 public void writeDescriptor(int clientIf, String address, int srvcType, 337 int srvcInstanceId, ParcelUuid srvcId, 338 int charInstanceId, ParcelUuid charId, 339 ParcelUuid descrId, int writeType, 340 int authReq, byte[] value) { 341 GattService service = getService(); 342 if (service == null) return; 343 service.writeDescriptor(clientIf, address, srvcType, srvcInstanceId, 344 srvcId.getUuid(), charInstanceId, 345 charId.getUuid(), descrId.getUuid(), 346 writeType, authReq, value); 347 } 348 349 public void beginReliableWrite(int clientIf, String address) { 350 GattService service = getService(); 351 if (service == null) return; 352 service.beginReliableWrite(clientIf, address); 353 } 354 355 public void endReliableWrite(int clientIf, String address, boolean execute) { 356 GattService service = getService(); 357 if (service == null) return; 358 service.endReliableWrite(clientIf, address, execute); 359 } 360 361 public void registerForNotification(int clientIf, String address, int srvcType, 362 int srvcInstanceId, ParcelUuid srvcId, 363 int charInstanceId, ParcelUuid charId, 364 boolean enable) { 365 GattService service = getService(); 366 if (service == null) return; 367 service.registerForNotification(clientIf, address, srvcType, srvcInstanceId, 368 srvcId.getUuid(), charInstanceId, 369 charId.getUuid(), enable); 370 } 371 372 public void readRemoteRssi(int clientIf, String address) { 373 GattService service = getService(); 374 if (service == null) return; 375 service.readRemoteRssi(clientIf, address); 376 } 377 378 public void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback) { 379 GattService service = getService(); 380 if (service == null) return; 381 service.registerServer(uuid.getUuid(), callback); 382 } 383 384 public void unregisterServer(int serverIf) { 385 GattService service = getService(); 386 if (service == null) return; 387 service.unregisterServer(serverIf); 388 } 389 390 public void serverConnect(int serverIf, String address, boolean isDirect) { 391 GattService service = getService(); 392 if (service == null) return; 393 service.serverConnect(serverIf, address, isDirect); 394 } 395 396 public void serverDisconnect(int serverIf, String address) { 397 GattService service = getService(); 398 if (service == null) return; 399 service.serverDisconnect(serverIf, address); 400 } 401 402 public void beginServiceDeclaration(int serverIf, int srvcType, 403 int srvcInstanceId, int minHandles, 404 ParcelUuid srvcId) { 405 GattService service = getService(); 406 if (service == null) return; 407 service.beginServiceDeclaration(serverIf, srvcType, srvcInstanceId, 408 minHandles, srvcId.getUuid()); 409 } 410 411 public void addIncludedService(int serverIf, int srvcType, 412 int srvcInstanceId, ParcelUuid srvcId) { 413 GattService service = getService(); 414 if (service == null) return; 415 service.addIncludedService(serverIf, srvcType, srvcInstanceId, 416 srvcId.getUuid()); 417 } 418 419 public void addCharacteristic(int serverIf, ParcelUuid charId, 420 int properties, int permissions) { 421 GattService service = getService(); 422 if (service == null) return; 423 service.addCharacteristic(serverIf, charId.getUuid(), properties, 424 permissions); 425 } 426 427 public void addDescriptor(int serverIf, ParcelUuid descId, 428 int permissions) { 429 GattService service = getService(); 430 if (service == null) return; 431 service.addDescriptor(serverIf, descId.getUuid(), permissions); 432 } 433 434 public void endServiceDeclaration(int serverIf) { 435 GattService service = getService(); 436 if (service == null) return; 437 service.endServiceDeclaration(serverIf); 438 } 439 440 public void removeService(int serverIf, int srvcType, 441 int srvcInstanceId, ParcelUuid srvcId) { 442 GattService service = getService(); 443 if (service == null) return; 444 service.removeService(serverIf, srvcType, srvcInstanceId, 445 srvcId.getUuid()); 446 } 447 448 public void clearServices(int serverIf) { 449 GattService service = getService(); 450 if (service == null) return; 451 service.clearServices(serverIf); 452 } 453 454 public void sendResponse(int serverIf, String address, int requestId, 455 int status, int offset, byte[] value) { 456 GattService service = getService(); 457 if (service == null) return; 458 service.sendResponse(serverIf, address, requestId, status, offset, value); 459 } 460 461 public void sendNotification(int serverIf, String address, int srvcType, 462 int srvcInstanceId, ParcelUuid srvcId, 463 int charInstanceId, ParcelUuid charId, 464 boolean confirm, byte[] value) { 465 GattService service = getService(); 466 if (service == null) return; 467 service.sendNotification(serverIf, address, srvcType, srvcInstanceId, 468 srvcId.getUuid(), charInstanceId, charId.getUuid(), confirm, value); 469 } 470 471 }; 472 473 /************************************************************************** 474 * Callback functions - CLIENT 475 *************************************************************************/ 476 477 void onScanResult(String address, int rssi, byte[] adv_data) { 478 if (DBG) Log.d(TAG, "onScanResult() - address=" + address 479 + ", rssi=" + rssi); 480 481 List<UUID> remoteUuids = parseUuids(adv_data); 482 for (ScanClient client : mScanQueue) { 483 if (client.uuids.length > 0) { 484 int matches = 0; 485 for (UUID search : client.uuids) { 486 for (UUID remote: remoteUuids) { 487 if (remote.equals(search)) { 488 ++matches; 489 break; // Only count 1st match in case of duplicates 490 } 491 } 492 } 493 494 if (matches < client.uuids.length) continue; 495 } 496 497 if (!client.isServer) { 498 ClientMap.App app = mClientMap.getById(client.appIf); 499 if (app != null) { 500 try { 501 app.callback.onScanResult(address, rssi, adv_data); 502 } catch (RemoteException e) { 503 Log.e(TAG, "Exception: " + e); 504 mClientMap.remove(client.appIf); 505 mScanQueue.remove(client); 506 } 507 } 508 } else { 509 ServerMap.App app = mServerMap.getById(client.appIf); 510 if (app != null) { 511 try { 512 app.callback.onScanResult(address, rssi, adv_data); 513 } catch (RemoteException e) { 514 Log.e(TAG, "Exception: " + e); 515 mServerMap.remove(client.appIf); 516 mScanQueue.remove(client); 517 } 518 } 519 } 520 } 521 } 522 523 void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb) 524 throws RemoteException { 525 UUID uuid = new UUID(uuidMsb, uuidLsb); 526 if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf); 527 ClientMap.App app = mClientMap.getByUuid(uuid); 528 if (app != null) { 529 app.id = clientIf; 530 app.linkToDeath(new ClientDeathRecipient(clientIf)); 531 app.callback.onClientRegistered(status, clientIf); 532 } 533 } 534 535 void onConnected(int clientIf, int connId, int status, String address) 536 throws RemoteException { 537 if (DBG) Log.d(TAG, "onConnected() - clientIf=" + clientIf 538 + ", connId=" + connId + ", address=" + address); 539 540 if (status == 0) mClientMap.addConnection(clientIf, connId, address); 541 ClientMap.App app = mClientMap.getById(clientIf); 542 if (app != null) { 543 app.callback.onClientConnectionState(status, clientIf, true, address); 544 } 545 } 546 547 void onDisconnected(int clientIf, int connId, int status, String address) 548 throws RemoteException { 549 if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf 550 + ", connId=" + connId + ", address=" + address); 551 552 mClientMap.removeConnection(clientIf, connId); 553 mSearchQueue.removeConnId(connId); 554 ClientMap.App app = mClientMap.getById(clientIf); 555 if (app != null) { 556 app.callback.onClientConnectionState(status, clientIf, false, address); 557 } 558 } 559 560 void onSearchCompleted(int connId, int status) throws RemoteException { 561 if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status); 562 // We got all services, now let's explore characteristics... 563 continueSearch(connId, status); 564 } 565 566 void onSearchResult(int connId, int srvcType, 567 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb) 568 throws RemoteException { 569 UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb); 570 String address = mClientMap.addressByConnId(connId); 571 572 if (DBG) Log.d(TAG, "onSearchResult() - address=" + address + ", uuid=" + uuid); 573 574 mSearchQueue.add(connId, srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb); 575 576 ClientMap.App app = mClientMap.getByConnId(connId); 577 if (app != null) { 578 app.callback.onGetService(address, srvcType, srvcInstId, 579 new ParcelUuid(uuid)); 580 } 581 } 582 583 void onGetCharacteristic(int connId, int status, int srvcType, 584 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 585 int charInstId, long charUuidLsb, long charUuidMsb, 586 int charProp) throws RemoteException { 587 588 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 589 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 590 String address = mClientMap.addressByConnId(connId); 591 592 if (DBG) Log.d(TAG, "onGetCharacteristic() - address=" + address 593 + ", status=" + status + ", charUuid=" + charUuid + ", prop=" + charProp); 594 595 if (status == 0) { 596 mSearchQueue.add(connId, srvcType, 597 srvcInstId, srvcUuidLsb, srvcUuidMsb, 598 charInstId, charUuidLsb, charUuidMsb); 599 600 ClientMap.App app = mClientMap.getByConnId(connId); 601 if (app != null) { 602 app.callback.onGetCharacteristic(address, srvcType, 603 srvcInstId, new ParcelUuid(srvcUuid), 604 charInstId, new ParcelUuid(charUuid), charProp); 605 } 606 607 // Get next characteristic in the current service 608 gattClientGetCharacteristicNative(connId, srvcType, 609 srvcInstId, srvcUuidLsb, srvcUuidMsb, 610 charInstId, charUuidLsb, charUuidMsb); 611 } else { 612 // Check for included services next 613 gattClientGetIncludedServiceNative(connId, 614 srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb, 615 0,0,0,0); 616 } 617 } 618 619 void onGetDescriptor(int connId, int status, int srvcType, 620 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 621 int charInstId, long charUuidLsb, long charUuidMsb, 622 long descrUuidLsb, long descrUuidMsb) throws RemoteException { 623 624 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 625 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 626 UUID descUuid = new UUID(descrUuidMsb, descrUuidLsb); 627 String address = mClientMap.addressByConnId(connId); 628 629 if (DBG) Log.d(TAG, "onGetDescriptor() - address=" + address 630 + ", status=" + status + ", descUuid=" + descUuid); 631 632 if (status == 0) { 633 ClientMap.App app = mClientMap.getByConnId(connId); 634 if (app != null) { 635 app.callback.onGetDescriptor(address, srvcType, 636 srvcInstId, new ParcelUuid(srvcUuid), 637 charInstId, new ParcelUuid(charUuid), 638 new ParcelUuid(descUuid)); 639 } 640 641 // Get next descriptor for the current characteristic 642 gattClientGetDescriptorNative(connId, srvcType, 643 srvcInstId, srvcUuidLsb, srvcUuidMsb, 644 charInstId, charUuidLsb, charUuidMsb, 645 descrUuidLsb, descrUuidMsb); 646 } else { 647 // Explore the next service 648 continueSearch(connId, 0); 649 } 650 } 651 652 void onGetIncludedService(int connId, int status, int srvcType, 653 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, int inclSrvcType, 654 int inclSrvcInstId, long inclSrvcUuidLsb, long inclSrvcUuidMsb) 655 throws RemoteException { 656 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 657 UUID inclSrvcUuid = new UUID(inclSrvcUuidMsb, inclSrvcUuidLsb); 658 String address = mClientMap.addressByConnId(connId); 659 660 if (DBG) Log.d(TAG, "onGetIncludedService() - address=" + address 661 + ", status=" + status + ", uuid=" + srvcUuid 662 + ", inclUuid=" + inclSrvcUuid); 663 664 if (status == 0) { 665 ClientMap.App app = mClientMap.getByConnId(connId); 666 if (app != null) { 667 app.callback.onGetIncludedService(address, 668 srvcType, srvcInstId, new ParcelUuid(srvcUuid), 669 inclSrvcType, inclSrvcInstId, new ParcelUuid(inclSrvcUuid)); 670 } 671 672 // Find additional included services 673 gattClientGetIncludedServiceNative(connId, 674 srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb, 675 inclSrvcType, inclSrvcInstId, inclSrvcUuidLsb, inclSrvcUuidMsb); 676 } else { 677 // Discover descriptors now 678 continueSearch(connId, 0); 679 } 680 } 681 682 void onRegisterForNotifications(int connId, int status, int registered, int srvcType, 683 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 684 int charInstId, long charUuidLsb, long charUuidMsb) { 685 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 686 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 687 String address = mClientMap.addressByConnId(connId); 688 689 if (DBG) Log.d(TAG, "onRegisterForNotifications() - address=" + address 690 + ", status=" + status + ", registered=" + registered 691 + ", charUuid=" + charUuid); 692 } 693 694 void onNotify(int connId, String address, int srvcType, 695 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 696 int charInstId, long charUuidLsb, long charUuidMsb, 697 boolean isNotify, byte[] data) throws RemoteException { 698 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 699 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 700 701 if (DBG) Log.d(TAG, "onNotify() - address=" + address 702 + ", charUuid=" + charUuid + ", length=" + data.length); 703 704 ClientMap.App app = mClientMap.getByConnId(connId); 705 if (app != null) { 706 app.callback.onNotify(address, srvcType, 707 srvcInstId, new ParcelUuid(srvcUuid), 708 charInstId, new ParcelUuid(charUuid), 709 data); 710 } 711 } 712 713 void onReadCharacteristic(int connId, int status, int srvcType, 714 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 715 int charInstId, long charUuidLsb, long charUuidMsb, 716 int charType, byte[] data) throws RemoteException { 717 718 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 719 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 720 String address = mClientMap.addressByConnId(connId); 721 722 if (DBG) Log.d(TAG, "onReadCharacteristic() - address=" + address 723 + ", status=" + status + ", length=" + data.length); 724 725 ClientMap.App app = mClientMap.getByConnId(connId); 726 if (app != null) { 727 app.callback.onCharacteristicRead(address, status, srvcType, 728 srvcInstId, new ParcelUuid(srvcUuid), 729 charInstId, new ParcelUuid(charUuid), data); 730 } 731 } 732 733 void onWriteCharacteristic(int connId, int status, int srvcType, 734 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 735 int charInstId, long charUuidLsb, long charUuidMsb) 736 throws RemoteException { 737 738 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 739 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 740 String address = mClientMap.addressByConnId(connId); 741 742 if (DBG) Log.d(TAG, "onWriteCharacteristic() - address=" + address 743 + ", status=" + status); 744 745 ClientMap.App app = mClientMap.getByConnId(connId); 746 if (app != null) { 747 app.callback.onCharacteristicWrite(address, status, srvcType, 748 srvcInstId, new ParcelUuid(srvcUuid), 749 charInstId, new ParcelUuid(charUuid)); 750 } 751 } 752 753 void onExecuteCompleted(int connId, int status) throws RemoteException { 754 String address = mClientMap.addressByConnId(connId); 755 if (DBG) Log.d(TAG, "onExecuteCompleted() - address=" + address 756 + ", status=" + status); 757 758 ClientMap.App app = mClientMap.getByConnId(connId); 759 if (app != null) { 760 app.callback.onExecuteWrite(address, status); 761 } 762 } 763 764 void onReadDescriptor(int connId, int status, int srvcType, 765 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 766 int charInstId, long charUuidLsb, long charUuidMsb, 767 long descrUuidLsb, long descrUuidMsb, 768 int charType, byte[] data) throws RemoteException { 769 770 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 771 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 772 UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb); 773 String address = mClientMap.addressByConnId(connId); 774 775 if (DBG) Log.d(TAG, "onReadDescriptor() - address=" + address 776 + ", status=" + status + ", length=" + data.length); 777 778 ClientMap.App app = mClientMap.getByConnId(connId); 779 if (app != null) { 780 app.callback.onDescriptorRead(address, status, srvcType, 781 srvcInstId, new ParcelUuid(srvcUuid), 782 charInstId, new ParcelUuid(charUuid), 783 new ParcelUuid(descrUuid), data); 784 } 785 } 786 787 void onWriteDescriptor(int connId, int status, int srvcType, 788 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 789 int charInstId, long charUuidLsb, long charUuidMsb, 790 long descrUuidLsb, long descrUuidMsb) throws RemoteException { 791 792 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 793 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 794 UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb); 795 String address = mClientMap.addressByConnId(connId); 796 797 if (DBG) Log.d(TAG, "onWriteDescriptor() - address=" + address 798 + ", status=" + status); 799 800 ClientMap.App app = mClientMap.getByConnId(connId); 801 if (app != null) { 802 app.callback.onDescriptorWrite(address, status, srvcType, 803 srvcInstId, new ParcelUuid(srvcUuid), 804 charInstId, new ParcelUuid(charUuid), 805 new ParcelUuid(descrUuid)); 806 } 807 } 808 809 void onReadRemoteRssi(int clientIf, String address, 810 int rssi, int status) throws RemoteException{ 811 if (DBG) Log.d(TAG, "onReadRemoteRssi() - clientIf=" + clientIf + " address=" + 812 address + ", rssi=" + rssi + ", status=" + status); 813 814 ClientMap.App app = mClientMap.getById(clientIf); 815 if (app != null) { 816 app.callback.onReadRemoteRssi(address, rssi, status); 817 } 818 } 819 820 /************************************************************************** 821 * GATT Service functions - Shared CLIENT/SERVER 822 *************************************************************************/ 823 824 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 825 final int DEVICE_TYPE_BREDR = 0x1; 826 827 Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice, 828 Integer>(); 829 830 // Add paired LE devices 831 832 Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); 833 for (BluetoothDevice device : bondedDevices) { 834 if (getDeviceType(device) != DEVICE_TYPE_BREDR) { 835 deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED); 836 } 837 } 838 839 // Add connected deviceStates 840 841 Set<String> connectedDevices = new HashSet<String>(); 842 connectedDevices.addAll(mClientMap.getConnectedDevices()); 843 connectedDevices.addAll(mServerMap.getConnectedDevices()); 844 845 for (String address : connectedDevices ) { 846 BluetoothDevice device = mAdapter.getRemoteDevice(address); 847 if (device != null) { 848 deviceStates.put(device, BluetoothProfile.STATE_CONNECTED); 849 } 850 } 851 852 // Create matching device sub-set 853 854 List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); 855 856 for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) { 857 for(int state : states) { 858 if (entry.getValue() == state) { 859 deviceList.add(entry.getKey()); 860 } 861 } 862 } 863 864 return deviceList; 865 } 866 867 void startScan(int appIf, boolean isServer) { 868 if (DBG) Log.d(TAG, "startScan() - queue=" + mScanQueue.size()); 869 870 if (getScanClient(appIf, isServer) == null) { 871 if (DBG) Log.d(TAG, "startScan() - adding client=" + appIf); 872 mScanQueue.add(new ScanClient(appIf, isServer)); 873 } 874 875 gattClientScanNative(appIf, true); 876 } 877 878 void startScanWithUuids(int appIf, boolean isServer, UUID[] uuids) { 879 if (DBG) Log.d(TAG, "startScanWithUuids() - queue=" + mScanQueue.size()); 880 881 if (getScanClient(appIf, isServer) == null) { 882 if (DBG) Log.d(TAG, "startScanWithUuids() - adding client=" + appIf); 883 mScanQueue.add(new ScanClient(appIf, isServer, uuids)); 884 } 885 886 gattClientScanNative(appIf, true); 887 } 888 889 void stopScan(int appIf, boolean isServer) { 890 if (DBG) Log.d(TAG, "stopScan() - queue=" + mScanQueue.size()); 891 892 removeScanClient(appIf, isServer); 893 894 if (mScanQueue.isEmpty()) { 895 if (DBG) Log.d(TAG, "stopScan() - queue empty; stopping scan"); 896 gattClientScanNative(appIf, false); 897 } 898 } 899 900 /************************************************************************** 901 * GATT Service functions - CLIENT 902 *************************************************************************/ 903 904 void registerClient(UUID uuid, IBluetoothGattCallback callback) { 905 if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid); 906 mClientMap.add(uuid, callback); 907 gattClientRegisterAppNative(uuid.getLeastSignificantBits(), 908 uuid.getMostSignificantBits()); 909 } 910 911 void unregisterClient(int clientIf) { 912 if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf); 913 removeScanClient(clientIf, false); 914 mClientMap.remove(clientIf); 915 gattClientUnregisterAppNative(clientIf); 916 } 917 918 void clientConnect(int clientIf, String address, boolean isDirect) { 919 if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect); 920 gattClientConnectNative(clientIf, address, isDirect); 921 } 922 923 void clientDisconnect(int clientIf, String address) { 924 Integer connId = mClientMap.connIdByAddress(clientIf, address); 925 if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId); 926 927 gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0); 928 } 929 930 List<String> getConnectedDevices() { 931 Set<String> connectedDevAddress = new HashSet<String>(); 932 connectedDevAddress.addAll(mClientMap.getConnectedDevices()); 933 connectedDevAddress.addAll(mServerMap.getConnectedDevices()); 934 List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress); 935 return connectedDeviceList; 936 } 937 938 void refreshDevice(int clientIf, String address) { 939 if (DBG) Log.d(TAG, "refreshDevice() - address=" + address); 940 gattClientRefreshNative(clientIf, address); 941 } 942 943 void discoverServices(int clientIf, String address) { 944 Integer connId = mClientMap.connIdByAddress(clientIf, address); 945 if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId); 946 947 if (connId != null) 948 gattClientSearchServiceNative(connId, true, 0, 0); 949 else 950 Log.e(TAG, "discoverServices() - No connection for " + address + "..."); 951 } 952 953 void readCharacteristic(int clientIf, String address, int srvcType, 954 int srvcInstanceId, UUID srvcUuid, 955 int charInstanceId, UUID charUuid, int authReq) { 956 if (DBG) Log.d(TAG, "readCharacteristic() - address=" + address); 957 958 Integer connId = mClientMap.connIdByAddress(clientIf, address); 959 if (connId != null) 960 gattClientReadCharacteristicNative(connId, srvcType, 961 srvcInstanceId, srvcUuid.getLeastSignificantBits(), 962 srvcUuid.getMostSignificantBits(), charInstanceId, 963 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 964 authReq); 965 else 966 Log.e(TAG, "readCharacteristic() - No connection for " + address + "..."); 967 } 968 969 void writeCharacteristic(int clientIf, String address, int srvcType, 970 int srvcInstanceId, UUID srvcUuid, 971 int charInstanceId, UUID charUuid, int writeType, 972 int authReq, byte[] value) { 973 if (DBG) Log.d(TAG, "writeCharacteristic() - address=" + address); 974 975 if (mReliableQueue.contains(address)) writeType = 3; // Prepared write 976 977 Integer connId = mClientMap.connIdByAddress(clientIf, address); 978 if (connId != null) 979 gattClientWriteCharacteristicNative(connId, srvcType, 980 srvcInstanceId, srvcUuid.getLeastSignificantBits(), 981 srvcUuid.getMostSignificantBits(), charInstanceId, 982 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 983 writeType, authReq, value); 984 else 985 Log.e(TAG, "writeCharacteristic() - No connection for " + address + "..."); 986 } 987 988 void readDescriptor(int clientIf, String address, int srvcType, 989 int srvcInstanceId, UUID srvcUuid, 990 int charInstanceId, UUID charUuid, 991 UUID descrUuid, int authReq) { 992 if (DBG) Log.d(TAG, "readDescriptor() - address=" + address); 993 994 Integer connId = mClientMap.connIdByAddress(clientIf, address); 995 if (connId != null) 996 gattClientReadDescriptorNative(connId, srvcType, 997 srvcInstanceId, srvcUuid.getLeastSignificantBits(), 998 srvcUuid.getMostSignificantBits(), charInstanceId, 999 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 1000 descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(), 1001 authReq); 1002 else 1003 Log.e(TAG, "readDescriptor() - No connection for " + address + "..."); 1004 }; 1005 1006 void writeDescriptor(int clientIf, String address, int srvcType, 1007 int srvcInstanceId, UUID srvcUuid, 1008 int charInstanceId, UUID charUuid, 1009 UUID descrUuid, int writeType, 1010 int authReq, byte[] value) { 1011 if (DBG) Log.d(TAG, "writeDescriptor() - address=" + address); 1012 1013 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1014 if (connId != null) 1015 gattClientWriteDescriptorNative(connId, srvcType, 1016 srvcInstanceId, srvcUuid.getLeastSignificantBits(), 1017 srvcUuid.getMostSignificantBits(), charInstanceId, 1018 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 1019 descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(), 1020 writeType, authReq, value); 1021 else 1022 Log.e(TAG, "writeDescriptor() - No connection for " + address + "..."); 1023 } 1024 1025 void beginReliableWrite(int clientIf, String address) { 1026 if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address); 1027 mReliableQueue.add(address); 1028 } 1029 1030 void endReliableWrite(int clientIf, String address, boolean execute) { 1031 if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address 1032 + " execute: " + execute); 1033 mReliableQueue.remove(address); 1034 1035 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1036 if (connId != null) gattClientExecuteWriteNative(connId, execute); 1037 } 1038 1039 void registerForNotification(int clientIf, String address, int srvcType, 1040 int srvcInstanceId, UUID srvcUuid, 1041 int charInstanceId, UUID charUuid, 1042 boolean enable) { 1043 if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable); 1044 1045 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1046 if (connId != null) { 1047 gattClientRegisterForNotificationsNative(clientIf, address, 1048 srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(), 1049 srvcUuid.getMostSignificantBits(), charInstanceId, 1050 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 1051 enable); 1052 } else { 1053 Log.e(TAG, "registerForNotification() - No connection for " + address + "..."); 1054 } 1055 } 1056 1057 void readRemoteRssi(int clientIf, String address) { 1058 if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address); 1059 gattClientReadRemoteRssiNative(clientIf, address); 1060 } 1061 1062 /************************************************************************** 1063 * Callback functions - SERVER 1064 *************************************************************************/ 1065 1066 void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb) 1067 throws RemoteException { 1068 1069 UUID uuid = new UUID(uuidMsb, uuidLsb); 1070 if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf); 1071 ServerMap.App app = mServerMap.getByUuid(uuid); 1072 if (app != null) { 1073 app.id = serverIf; 1074 app.linkToDeath(new ServerDeathRecipient(serverIf)); 1075 app.callback.onServerRegistered(status, serverIf); 1076 } 1077 } 1078 1079 void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId, 1080 long srvcUuidLsb, long srvcUuidMsb, int srvcHandle) 1081 throws RemoteException { 1082 UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb); 1083 if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status 1084 + ", handle=" + srvcHandle); 1085 if (status == 0) 1086 mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId); 1087 continueServiceDeclaration(serverIf, status, srvcHandle); 1088 } 1089 1090 void onIncludedServiceAdded(int status, int serverIf, int srvcHandle, 1091 int includedSrvcHandle) throws RemoteException { 1092 if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status 1093 + ", service=" + srvcHandle + ", included=" + includedSrvcHandle); 1094 continueServiceDeclaration(serverIf, status, srvcHandle); 1095 } 1096 1097 void onCharacteristicAdded(int status, int serverIf, 1098 long charUuidLsb, long charUuidMsb, 1099 int srvcHandle, int charHandle) 1100 throws RemoteException { 1101 UUID uuid = new UUID(charUuidMsb, charUuidLsb); 1102 if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status 1103 + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle); 1104 if (status == 0) 1105 mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle); 1106 continueServiceDeclaration(serverIf, status, srvcHandle); 1107 } 1108 1109 void onDescriptorAdded(int status, int serverIf, 1110 long descrUuidLsb, long descrUuidMsb, 1111 int srvcHandle, int descrHandle) 1112 throws RemoteException { 1113 UUID uuid = new UUID(descrUuidMsb, descrUuidLsb); 1114 if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status 1115 + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle); 1116 if (status == 0) 1117 mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle); 1118 continueServiceDeclaration(serverIf, status, srvcHandle); 1119 } 1120 1121 void onServiceStarted(int status, int serverIf, int srvcHandle) 1122 throws RemoteException { 1123 if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle 1124 + ", status=" + status); 1125 if (status == 0) 1126 mHandleMap.setStarted(serverIf, srvcHandle, true); 1127 } 1128 1129 void onServiceStopped(int status, int serverIf, int srvcHandle) 1130 throws RemoteException { 1131 if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle 1132 + ", status=" + status); 1133 if (status == 0) 1134 mHandleMap.setStarted(serverIf, srvcHandle, false); 1135 stopNextService(serverIf, status); 1136 } 1137 1138 void onServiceDeleted(int status, int serverIf, int srvcHandle) { 1139 if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle 1140 + ", status=" + status); 1141 mHandleMap.deleteService(serverIf, srvcHandle); 1142 } 1143 1144 void onClientConnected(String address, boolean connected, int connId, int serverIf) 1145 throws RemoteException { 1146 1147 if (DBG) Log.d(TAG, "onConnected() connId=" + connId 1148 + ", address=" + address + ", connected=" + connected); 1149 1150 ServerMap.App app = mServerMap.getById(serverIf); 1151 if (app == null) return; 1152 1153 if (connected) { 1154 mServerMap.addConnection(serverIf, connId, address); 1155 } else { 1156 mServerMap.removeConnection(serverIf, connId); 1157 } 1158 1159 app.callback.onServerConnectionState((byte)0, serverIf, connected, address); 1160 } 1161 1162 void onAttributeRead(String address, int connId, int transId, 1163 int attrHandle, int offset, boolean isLong) 1164 throws RemoteException { 1165 if (DBG) Log.d(TAG, "onAttributeRead() connId=" + connId 1166 + ", address=" + address + ", handle=" + attrHandle 1167 + ", requestId=" + transId + ", offset=" + offset); 1168 1169 HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle); 1170 if (entry == null) return; 1171 1172 if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid 1173 + ", serverIf=" + entry.serverIf + ", type=" + entry.type); 1174 1175 mHandleMap.addRequest(transId, attrHandle); 1176 1177 ServerMap.App app = mServerMap.getById(entry.serverIf); 1178 if (app == null) return; 1179 1180 switch(entry.type) { 1181 case HandleMap.TYPE_CHARACTERISTIC: 1182 { 1183 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1184 app.callback.onCharacteristicReadRequest(address, transId, offset, isLong, 1185 serviceEntry.serviceType, serviceEntry.instance, 1186 new ParcelUuid(serviceEntry.uuid), entry.instance, 1187 new ParcelUuid(entry.uuid)); 1188 break; 1189 } 1190 1191 case HandleMap.TYPE_DESCRIPTOR: 1192 { 1193 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1194 HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle); 1195 app.callback.onDescriptorReadRequest(address, transId, offset, isLong, 1196 serviceEntry.serviceType, serviceEntry.instance, 1197 new ParcelUuid(serviceEntry.uuid), charEntry.instance, 1198 new ParcelUuid(charEntry.uuid), 1199 new ParcelUuid(entry.uuid)); 1200 break; 1201 } 1202 1203 default: 1204 Log.e(TAG, "onAttributeRead() - Requested unknown attribute type."); 1205 break; 1206 } 1207 } 1208 1209 void onAttributeWrite(String address, int connId, int transId, 1210 int attrHandle, int offset, int length, 1211 boolean needRsp, boolean isPrep, 1212 byte[] data) 1213 throws RemoteException { 1214 if (DBG) Log.d(TAG, "onAttributeWrite() connId=" + connId 1215 + ", address=" + address + ", handle=" + attrHandle 1216 + ", requestId=" + transId + ", isPrep=" + isPrep 1217 + ", offset=" + offset); 1218 1219 HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle); 1220 if (entry == null) return; 1221 1222 if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid 1223 + ", serverIf=" + entry.serverIf + ", type=" + entry.type); 1224 1225 mHandleMap.addRequest(transId, attrHandle); 1226 1227 ServerMap.App app = mServerMap.getById(entry.serverIf); 1228 if (app == null) return; 1229 1230 switch(entry.type) { 1231 case HandleMap.TYPE_CHARACTERISTIC: 1232 { 1233 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1234 app.callback.onCharacteristicWriteRequest(address, transId, 1235 offset, length, isPrep, needRsp, 1236 serviceEntry.serviceType, serviceEntry.instance, 1237 new ParcelUuid(serviceEntry.uuid), entry.instance, 1238 new ParcelUuid(entry.uuid), data); 1239 break; 1240 } 1241 1242 case HandleMap.TYPE_DESCRIPTOR: 1243 { 1244 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1245 HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle); 1246 app.callback.onDescriptorWriteRequest(address, transId, 1247 offset, length, isPrep, needRsp, 1248 serviceEntry.serviceType, serviceEntry.instance, 1249 new ParcelUuid(serviceEntry.uuid), charEntry.instance, 1250 new ParcelUuid(charEntry.uuid), 1251 new ParcelUuid(entry.uuid), data); 1252 break; 1253 } 1254 1255 default: 1256 Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type."); 1257 break; 1258 } 1259 } 1260 1261 void onExecuteWrite(String address, int connId, int transId, int execWrite) 1262 throws RemoteException { 1263 if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId 1264 + ", address=" + address + ", transId=" + transId); 1265 1266 ServerMap.App app = mServerMap.getByConnId(connId); 1267 if (app == null) return; 1268 1269 app.callback.onExecuteWrite(address, transId, execWrite == 1); 1270 } 1271 1272 void onResponseSendCompleted(int status, int attrHandle) { 1273 if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle); 1274 } 1275 1276 /************************************************************************** 1277 * GATT Service functions - SERVER 1278 *************************************************************************/ 1279 1280 void registerServer(UUID uuid, IBluetoothGattServerCallback callback) { 1281 if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid); 1282 mServerMap.add(uuid, callback); 1283 gattServerRegisterAppNative(uuid.getLeastSignificantBits(), 1284 uuid.getMostSignificantBits()); 1285 } 1286 1287 void unregisterServer(int serverIf) { 1288 if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf); 1289 1290 deleteServices(serverIf); 1291 1292 mServerMap.remove(serverIf); 1293 gattServerUnregisterAppNative(serverIf); 1294 } 1295 1296 void serverConnect(int serverIf, String address, boolean isDirect) { 1297 if (DBG) Log.d(TAG, "serverConnect() - address=" + address); 1298 gattServerConnectNative(serverIf, address, isDirect); 1299 } 1300 1301 void serverDisconnect(int serverIf, String address) { 1302 Integer connId = mServerMap.connIdByAddress(serverIf, address); 1303 if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId); 1304 1305 gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0); 1306 } 1307 1308 void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId, 1309 int minHandles, UUID srvcUuid) { 1310 if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid); 1311 ServiceDeclaration serviceDeclaration = addDeclaration(); 1312 serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles); 1313 } 1314 1315 void addIncludedService(int serverIf, int srvcType, int srvcInstanceId, 1316 UUID srvcUuid) { 1317 if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid); 1318 getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId); 1319 } 1320 1321 void addCharacteristic(int serverIf, UUID charUuid, int properties, 1322 int permissions) { 1323 if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid); 1324 getActiveDeclaration().addCharacteristic(charUuid, properties, permissions); 1325 } 1326 1327 void addDescriptor(int serverIf, UUID descUuid, int permissions) { 1328 if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid); 1329 getActiveDeclaration().addDescriptor(descUuid, permissions); 1330 } 1331 1332 void endServiceDeclaration(int serverIf) { 1333 if (DBG) Log.d(TAG, "endServiceDeclaration()"); 1334 1335 if (getActiveDeclaration() == getPendingDeclaration()) { 1336 try { 1337 continueServiceDeclaration(serverIf, (byte)0, 0); 1338 } catch (RemoteException e) { 1339 Log.e(TAG,""+e); 1340 } 1341 } 1342 } 1343 1344 void removeService(int serverIf, int srvcType, 1345 int srvcInstanceId, UUID srvcUuid) { 1346 if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid); 1347 1348 int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId); 1349 if (srvcHandle == 0) return; 1350 gattServerDeleteServiceNative(serverIf, srvcHandle); 1351 } 1352 1353 void clearServices(int serverIf) { 1354 if (DBG) Log.d(TAG, "clearServices()"); 1355 deleteServices(serverIf); 1356 } 1357 1358 void sendResponse(int serverIf, String address, int requestId, 1359 int status, int offset, byte[] value) { 1360 if (DBG) Log.d(TAG, "sendResponse() - address=" + address); 1361 1362 int handle = 0; 1363 HandleMap.Entry entry = mHandleMap.getByRequestId(requestId); 1364 if (entry != null) handle = entry.handle; 1365 1366 int connId = mServerMap.connIdByAddress(serverIf, address); 1367 gattServerSendResponseNative(serverIf, connId, requestId, (byte)status, 1368 handle, offset, value, (byte)0); 1369 mHandleMap.deleteRequest(requestId); 1370 } 1371 1372 void sendNotification(int serverIf, String address, int srvcType, 1373 int srvcInstanceId, UUID srvcUuid, 1374 int charInstanceId, UUID charUuid, 1375 boolean confirm, byte[] value) { 1376 if (DBG) Log.d(TAG, "sendNotification() - address=" + address); 1377 1378 int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId); 1379 if (srvcHandle == 0) return; 1380 1381 int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId); 1382 if (charHandle == 0) return; 1383 1384 int connId = mServerMap.connIdByAddress(serverIf, address); 1385 if (connId == 0) return; 1386 1387 if (confirm) { 1388 gattServerSendIndicationNative(serverIf, charHandle, connId, value); 1389 } else { 1390 gattServerSendNotificationNative(serverIf, charHandle, connId, value); 1391 } 1392 } 1393 1394 /************************************************************************** 1395 * Private functions 1396 *************************************************************************/ 1397 1398 private int getDeviceType(BluetoothDevice device) { 1399 int type = gattClientGetDeviceTypeNative(device.getAddress()); 1400 if (DBG) Log.d(TAG, "getDeviceType() - device=" + device 1401 + ", type=" + type); 1402 return type; 1403 } 1404 1405 private void continueSearch(int connId, int status) throws RemoteException { 1406 if (status == 0 && !mSearchQueue.isEmpty()) { 1407 SearchQueue.Entry svc = mSearchQueue.pop(); 1408 1409 if (svc.charUuidLsb == 0) { 1410 // Characteristic is up next 1411 gattClientGetCharacteristicNative(svc.connId, svc.srvcType, 1412 svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0); 1413 } else { 1414 // Descriptor is up next 1415 gattClientGetDescriptorNative(svc.connId, svc.srvcType, 1416 svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 1417 svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0,0); 1418 } 1419 } else { 1420 ClientMap.App app = mClientMap.getByConnId(connId); 1421 if (app != null) { 1422 app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status); 1423 } 1424 } 1425 } 1426 1427 private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException { 1428 if (mServiceDeclarations.size() == 0) return; 1429 if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle); 1430 1431 boolean finished = false; 1432 1433 ServiceDeclaration.Entry entry = null; 1434 if (status == 0) 1435 entry = getPendingDeclaration().getNext(); 1436 1437 if (entry != null) { 1438 if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type=" 1439 + entry.type); 1440 switch(entry.type) { 1441 case ServiceDeclaration.TYPE_SERVICE: 1442 gattServerAddServiceNative(serverIf, entry.serviceType, 1443 entry.instance, 1444 entry.uuid.getLeastSignificantBits(), 1445 entry.uuid.getMostSignificantBits(), 1446 getPendingDeclaration().getNumHandles()); 1447 break; 1448 1449 case ServiceDeclaration.TYPE_CHARACTERISTIC: 1450 gattServerAddCharacteristicNative(serverIf, srvcHandle, 1451 entry.uuid.getLeastSignificantBits(), 1452 entry.uuid.getMostSignificantBits(), 1453 entry.properties, entry.permissions); 1454 break; 1455 1456 case ServiceDeclaration.TYPE_DESCRIPTOR: 1457 gattServerAddDescriptorNative(serverIf, srvcHandle, 1458 entry.uuid.getLeastSignificantBits(), 1459 entry.uuid.getMostSignificantBits(), 1460 entry.permissions); 1461 break; 1462 1463 case ServiceDeclaration.TYPE_INCLUDED_SERVICE: 1464 { 1465 int inclSrvc = mHandleMap.getServiceHandle(entry.uuid, 1466 entry.serviceType, entry.instance); 1467 if (inclSrvc != 0) { 1468 gattServerAddIncludedServiceNative(serverIf, srvcHandle, 1469 inclSrvc); 1470 } else { 1471 finished = true; 1472 } 1473 break; 1474 } 1475 } 1476 } else { 1477 gattServerStartServiceNative(serverIf, srvcHandle, (byte)2 /*BREDR/LE*/); 1478 finished = true; 1479 } 1480 1481 if (finished) { 1482 if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed."); 1483 ServerMap.App app = mServerMap.getById(serverIf); 1484 if (app != null) { 1485 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle); 1486 if (serviceEntry != null) { 1487 app.callback.onServiceAdded(status, serviceEntry.serviceType, 1488 serviceEntry.instance, new ParcelUuid(serviceEntry.uuid)); 1489 } else { 1490 app.callback.onServiceAdded(status, 0, 0, null); 1491 } 1492 } 1493 removePendingDeclaration(); 1494 1495 if (getPendingDeclaration() != null) { 1496 continueServiceDeclaration(serverIf, (byte)0, 0); 1497 } 1498 } 1499 } 1500 1501 private void stopNextService(int serverIf, int status) throws RemoteException { 1502 if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf 1503 + ", status=" + status); 1504 1505 if (status == 0) { 1506 List<HandleMap.Entry> entries = mHandleMap.getEntries(); 1507 for(HandleMap.Entry entry : entries) { 1508 if (entry.type != HandleMap.TYPE_SERVICE || 1509 entry.serverIf != serverIf || 1510 entry.started == false) 1511 continue; 1512 1513 gattServerStopServiceNative(serverIf, entry.handle); 1514 return; 1515 } 1516 } 1517 } 1518 1519 private void deleteServices(int serverIf) { 1520 if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf); 1521 1522 /* 1523 * Figure out which handles to delete. 1524 * The handles are copied into a new list to avoid race conditions. 1525 */ 1526 List<Integer> handleList = new ArrayList<Integer>(); 1527 List<HandleMap.Entry> entries = mHandleMap.getEntries(); 1528 for(HandleMap.Entry entry : entries) { 1529 if (entry.type != HandleMap.TYPE_SERVICE || 1530 entry.serverIf != serverIf) 1531 continue; 1532 handleList.add(entry.handle); 1533 } 1534 1535 /* Now actually delete the services.... */ 1536 for(Integer handle : handleList) { 1537 gattServerDeleteServiceNative(serverIf, handle); 1538 } 1539 } 1540 1541 private List<UUID> parseUuids(byte[] adv_data) { 1542 List<UUID> uuids = new ArrayList<UUID>(); 1543 1544 int offset = 0; 1545 while(offset < (adv_data.length-2)) { 1546 int len = adv_data[offset++]; 1547 if (len == 0) break; 1548 1549 int type = adv_data[offset++]; 1550 switch (type) { 1551 case 0x02: // Partial list of 16-bit UUIDs 1552 case 0x03: // Complete list of 16-bit UUIDs 1553 while (len > 1) { 1554 int uuid16 = adv_data[offset++]; 1555 uuid16 += (adv_data[offset++] << 8); 1556 len -= 2; 1557 uuids.add(UUID.fromString(String.format( 1558 "%08x-0000-1000-8000-00805f9b34fb", uuid16))); 1559 } 1560 break; 1561 1562 default: 1563 offset += (len - 1); 1564 break; 1565 } 1566 } 1567 1568 return uuids; 1569 } 1570 1571 /************************************************************************** 1572 * GATT Test functions 1573 *************************************************************************/ 1574 1575 void gattTestCommand(int command, UUID uuid1, String bda1, 1576 int p1, int p2, int p3, int p4, int p5) { 1577 if (bda1 == null) bda1 = "00:00:00:00:00:00"; 1578 if (uuid1 != null) 1579 gattTestNative(command, uuid1.getLeastSignificantBits(), 1580 uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5); 1581 else 1582 gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5); 1583 } 1584 1585 private native void gattTestNative(int command, 1586 long uuid1_lsb, long uuid1_msb, String bda1, 1587 int p1, int p2, int p3, int p4, int p5); 1588 1589 /************************************************************************** 1590 * Native functions prototypes 1591 *************************************************************************/ 1592 1593 private native static void classInitNative(); 1594 private native void initializeNative(); 1595 private native void cleanupNative(); 1596 1597 private native int gattClientGetDeviceTypeNative(String address); 1598 1599 private native void gattClientRegisterAppNative(long app_uuid_lsb, 1600 long app_uuid_msb); 1601 1602 private native void gattClientUnregisterAppNative(int clientIf); 1603 1604 private native void gattClientScanNative(int clientIf, boolean start); 1605 1606 private native void gattClientConnectNative(int clientIf, String address, 1607 boolean isDirect); 1608 1609 private native void gattClientDisconnectNative(int clientIf, String address, 1610 int conn_id); 1611 1612 private native void gattClientRefreshNative(int clientIf, String address); 1613 1614 private native void gattClientSearchServiceNative(int conn_id, 1615 boolean search_all, long service_uuid_lsb, long service_uuid_msb); 1616 1617 private native void gattClientGetCharacteristicNative(int conn_id, 1618 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 1619 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 1620 long char_id_uuid_msb); 1621 1622 private native void gattClientGetDescriptorNative(int conn_id, 1623 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 1624 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 1625 long char_id_uuid_msb, long descr_id_uuid_lsb, long descr_id_uuid_msb); 1626 1627 private native void gattClientGetIncludedServiceNative(int conn_id, 1628 int service_type, int service_id_inst_id, 1629 long service_id_uuid_lsb, long service_id_uuid_msb, 1630 int incl_service_id_inst_id, int incl_service_type, 1631 long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb); 1632 1633 private native void gattClientReadCharacteristicNative(int conn_id, 1634 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 1635 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 1636 long char_id_uuid_msb, int authReq); 1637 1638 private native void gattClientReadDescriptorNative(int conn_id, 1639 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 1640 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 1641 long char_id_uuid_msb, long descr_id_uuid_lsb, long descr_id_uuid_msb, 1642 int authReq); 1643 1644 private native void gattClientWriteCharacteristicNative(int conn_id, 1645 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 1646 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 1647 long char_id_uuid_msb, int write_type, int auth_req, byte[] value); 1648 1649 private native void gattClientWriteDescriptorNative(int conn_id, 1650 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 1651 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 1652 long char_id_uuid_msb, long descr_id_uuid_lsb, long descr_id_uuid_msb, 1653 int write_type, int auth_req, byte[] value); 1654 1655 private native void gattClientExecuteWriteNative(int conn_id, boolean execute); 1656 1657 private native void gattClientRegisterForNotificationsNative(int clientIf, 1658 String address, int service_type, int service_id_inst_id, 1659 long service_id_uuid_lsb, long service_id_uuid_msb, 1660 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 1661 boolean enable); 1662 1663 private native void gattClientReadRemoteRssiNative(int clientIf, 1664 String address); 1665 1666 private native void gattServerRegisterAppNative(long app_uuid_lsb, 1667 long app_uuid_msb); 1668 1669 private native void gattServerUnregisterAppNative(int serverIf); 1670 1671 private native void gattServerConnectNative(int server_if, String address, 1672 boolean is_direct); 1673 1674 private native void gattServerDisconnectNative(int serverIf, String address, 1675 int conn_id); 1676 1677 private native void gattServerAddServiceNative (int server_if, 1678 int service_type, int service_id_inst_id, 1679 long service_id_uuid_lsb, long service_id_uuid_msb, 1680 int num_handles); 1681 1682 private native void gattServerAddIncludedServiceNative (int server_if, 1683 int svc_handle, int included_svc_handle); 1684 1685 private native void gattServerAddCharacteristicNative (int server_if, 1686 int svc_handle, long char_uuid_lsb, long char_uuid_msb, 1687 int properties, int permissions); 1688 1689 private native void gattServerAddDescriptorNative (int server_if, 1690 int svc_handle, long desc_uuid_lsb, long desc_uuid_msb, 1691 int permissions); 1692 1693 private native void gattServerStartServiceNative (int server_if, 1694 int svc_handle, int transport ); 1695 1696 private native void gattServerStopServiceNative (int server_if, 1697 int svc_handle); 1698 1699 private native void gattServerDeleteServiceNative (int server_if, 1700 int svc_handle); 1701 1702 private native void gattServerSendIndicationNative (int server_if, 1703 int attr_handle, int conn_id, byte[] val); 1704 1705 private native void gattServerSendNotificationNative (int server_if, 1706 int attr_handle, int conn_id, byte[] val); 1707 1708 private native void gattServerSendResponseNative (int server_if, 1709 int conn_id, int trans_id, int status, int handle, int offset, 1710 byte[] val, int auth_req); 1711} 1712