GattService.java revision e632e4bb8c873f102cac7d6f39585ea06f34c082
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.BluetoothGatt; 23import android.bluetooth.BluetoothProfile; 24import android.bluetooth.IBluetoothGatt; 25import android.bluetooth.IBluetoothGattCallback; 26import android.bluetooth.IBluetoothGattServerCallback; 27import android.bluetooth.le.AdvertiseCallback; 28import android.bluetooth.le.AdvertiseData; 29import android.bluetooth.le.AdvertiseSettings; 30import android.bluetooth.le.ResultStorageDescriptor; 31import android.bluetooth.le.ScanFilter; 32import android.bluetooth.le.ScanRecord; 33import android.bluetooth.le.ScanResult; 34import android.bluetooth.le.ScanSettings; 35import android.content.Intent; 36import android.os.IBinder; 37import android.os.ParcelUuid; 38import android.os.RemoteException; 39import android.os.SystemClock; 40import android.util.Log; 41 42import com.android.bluetooth.Utils; 43import com.android.bluetooth.btservice.AdapterService; 44import com.android.bluetooth.btservice.ProfileService; 45import com.android.bluetooth.util.NumberUtils; 46import com.android.internal.annotations.VisibleForTesting; 47 48import java.util.ArrayList; 49import java.util.Arrays; 50import java.util.Collections; 51import java.util.HashMap; 52import java.util.HashSet; 53import java.util.List; 54import java.util.Map; 55import java.util.Set; 56import java.util.UUID; 57import java.util.concurrent.TimeUnit; 58 59/** 60 * Provides Bluetooth Gatt profile, as a service in 61 * the Bluetooth application. 62 * @hide 63 */ 64public class GattService extends ProfileService { 65 private static final boolean DBG = GattServiceConfig.DBG; 66 private static final boolean VDBG = GattServiceConfig.VDBG; 67 private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService"; 68 69 static final int SCAN_FILTER_ENABLED = 1; 70 static final int SCAN_FILTER_MODIFIED = 2; 71 72 private static final int MAC_ADDRESS_LENGTH = 6; 73 // Batch scan related constants. 74 private static final int TRUNCATED_RESULT_SIZE = 11; 75 private static final int TIME_STAMP_LENGTH = 2; 76 77 // onFoundLost related constants 78 private static final int ADVT_STATE_ONFOUND = 0; 79 private static final int ADVT_STATE_ONLOST = 1; 80 81 /** 82 * Search queue to serialize remote onbject inspection. 83 */ 84 SearchQueue mSearchQueue = new SearchQueue(); 85 86 /** 87 * List of our registered clients. 88 */ 89 90 class ClientMap extends ContextMap<IBluetoothGattCallback> {} 91 ClientMap mClientMap = new ClientMap(); 92 93 /** 94 * List of our registered server apps. 95 */ 96 class ServerMap extends ContextMap<IBluetoothGattServerCallback> {} 97 ServerMap mServerMap = new ServerMap(); 98 99 /** 100 * Server handle map. 101 */ 102 HandleMap mHandleMap = new HandleMap(); 103 private List<UUID> mAdvertisingServiceUuids = new ArrayList<UUID>(); 104 105 private int mMaxScanFilters; 106 private Map<ScanClient, ScanResult> mOnFoundResults = new HashMap<ScanClient, ScanResult>(); 107 108 /** 109 * Pending service declaration queue 110 */ 111 private List<ServiceDeclaration> mServiceDeclarations = new ArrayList<ServiceDeclaration>(); 112 113 private ServiceDeclaration addDeclaration() { 114 synchronized (mServiceDeclarations) { 115 mServiceDeclarations.add(new ServiceDeclaration()); 116 } 117 return getActiveDeclaration(); 118 } 119 120 private ServiceDeclaration getActiveDeclaration() { 121 synchronized (mServiceDeclarations) { 122 if (mServiceDeclarations.size() > 0) 123 return mServiceDeclarations.get(mServiceDeclarations.size() - 1); 124 } 125 return null; 126 } 127 128 private ServiceDeclaration getPendingDeclaration() { 129 synchronized (mServiceDeclarations) { 130 if (mServiceDeclarations.size() > 0) 131 return mServiceDeclarations.get(0); 132 } 133 return null; 134 } 135 136 private void removePendingDeclaration() { 137 synchronized (mServiceDeclarations) { 138 if (mServiceDeclarations.size() > 0) 139 mServiceDeclarations.remove(0); 140 } 141 } 142 143 private AdvertiseManager mAdvertiseManager; 144 private ScanManager mScanManager; 145 146 /** 147 * Reliable write queue 148 */ 149 private Set<String> mReliableQueue = new HashSet<String>(); 150 151 static { 152 classInitNative(); 153 } 154 155 protected String getName() { 156 return TAG; 157 } 158 159 protected IProfileServiceBinder initBinder() { 160 return new BluetoothGattBinder(this); 161 } 162 163 protected boolean start() { 164 if (DBG) Log.d(TAG, "start()"); 165 initializeNative(); 166 mAdvertiseManager = new AdvertiseManager(this, AdapterService.getAdapterService()); 167 mAdvertiseManager.start(); 168 169 mScanManager = new ScanManager(this); 170 mScanManager.start(); 171 172 return true; 173 } 174 175 protected boolean stop() { 176 if (DBG) Log.d(TAG, "stop()"); 177 mClientMap.clear(); 178 mServerMap.clear(); 179 mSearchQueue.clear(); 180 mHandleMap.clear(); 181 mServiceDeclarations.clear(); 182 mReliableQueue.clear(); 183 if (mAdvertiseManager != null) mAdvertiseManager.cleanup(); 184 if (mScanManager != null) mScanManager.cleanup(); 185 return true; 186 } 187 188 protected boolean cleanup() { 189 if (DBG) Log.d(TAG, "cleanup()"); 190 cleanupNative(); 191 if (mAdvertiseManager != null) mAdvertiseManager.cleanup(); 192 if (mScanManager != null) mScanManager.cleanup(); 193 return true; 194 } 195 196 @Override 197 public int onStartCommand(Intent intent, int flags, int startId) { 198 if (GattDebugUtils.handleDebugAction(this, intent)) { 199 return Service.START_NOT_STICKY; 200 } 201 return super.onStartCommand(intent, flags, startId); 202 } 203 204 /** 205 * DeathReceipient handlers used to unregister applications that 206 * disconnect ungracefully (ie. crash or forced close). 207 */ 208 209 class ClientDeathRecipient implements IBinder.DeathRecipient { 210 int mAppIf; 211 212 public ClientDeathRecipient(int appIf) { 213 mAppIf = appIf; 214 } 215 216 @Override 217 public void binderDied() { 218 if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!"); 219 220 if (isScanClient(mAppIf)) { 221 ScanClient client = new ScanClient(mAppIf, false); 222 client.appDied = true; 223 stopScan(client); 224 } else { 225 AdvertiseClient client = new AdvertiseClient(mAppIf); 226 client.appDied = true; 227 stopMultiAdvertising(client); 228 } 229 } 230 231 private boolean isScanClient(int clientIf) { 232 for (ScanClient client : mScanManager.getRegularScanQueue()) { 233 if (client.clientIf == clientIf) { 234 return true; 235 } 236 } 237 for (ScanClient client : mScanManager.getBatchScanQueue()) { 238 if (client.clientIf == clientIf) { 239 return true; 240 } 241 } 242 return false; 243 } 244 } 245 246 class ServerDeathRecipient implements IBinder.DeathRecipient { 247 int mAppIf; 248 249 public ServerDeathRecipient(int appIf) { 250 mAppIf = appIf; 251 } 252 253 public void binderDied() { 254 if (DBG) Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!"); 255 unregisterServer(mAppIf); 256 } 257 } 258 259 /** 260 * Handlers for incoming service calls 261 */ 262 private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder { 263 private GattService mService; 264 265 public BluetoothGattBinder(GattService svc) { 266 mService = svc; 267 } 268 269 public boolean cleanup() { 270 mService = null; 271 return true; 272 } 273 274 private GattService getService() { 275 if (mService != null && mService.isAvailable()) return mService; 276 Log.e(TAG, "getService() - Service requested, but not available!"); 277 return null; 278 } 279 280 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 281 GattService service = getService(); 282 if (service == null) return new ArrayList<BluetoothDevice>(); 283 return service.getDevicesMatchingConnectionStates(states); 284 } 285 286 public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) { 287 GattService service = getService(); 288 if (service == null) return; 289 service.registerClient(uuid.getUuid(), callback); 290 } 291 292 public void unregisterClient(int clientIf) { 293 GattService service = getService(); 294 if (service == null) return; 295 service.unregisterClient(clientIf); 296 } 297 298 @Override 299 public void startScan(int appIf, boolean isServer, ScanSettings settings, 300 List<ScanFilter> filters, List storages) { 301 GattService service = getService(); 302 if (service == null) return; 303 service.startScan(appIf, isServer, settings, filters, storages); 304 } 305 306 public void stopScan(int appIf, boolean isServer) { 307 GattService service = getService(); 308 if (service == null) return; 309 service.stopScan(new ScanClient(appIf, isServer)); 310 } 311 312 @Override 313 public void flushPendingBatchResults(int appIf, boolean isServer) { 314 GattService service = getService(); 315 if (service == null) return; 316 service.flushPendingBatchResults(appIf, isServer); 317 } 318 319 public void clientConnect(int clientIf, String address, boolean isDirect, int transport) { 320 GattService service = getService(); 321 if (service == null) return; 322 service.clientConnect(clientIf, address, isDirect, transport); 323 } 324 325 public void clientDisconnect(int clientIf, String address) { 326 GattService service = getService(); 327 if (service == null) return; 328 service.clientDisconnect(clientIf, address); 329 } 330 331 public void refreshDevice(int clientIf, String address) { 332 GattService service = getService(); 333 if (service == null) return; 334 service.refreshDevice(clientIf, address); 335 } 336 337 public void discoverServices(int clientIf, String address) { 338 GattService service = getService(); 339 if (service == null) return; 340 service.discoverServices(clientIf, address); 341 } 342 343 public void readCharacteristic(int clientIf, String address, int srvcType, 344 int srvcInstanceId, ParcelUuid srvcId, 345 int charInstanceId, ParcelUuid charId, 346 int authReq) { 347 GattService service = getService(); 348 if (service == null) return; 349 service.readCharacteristic(clientIf, address, srvcType, srvcInstanceId, 350 srvcId.getUuid(), charInstanceId, 351 charId.getUuid(), authReq); 352 } 353 354 public void writeCharacteristic(int clientIf, String address, int srvcType, 355 int srvcInstanceId, ParcelUuid srvcId, 356 int charInstanceId, ParcelUuid charId, 357 int writeType, int authReq, byte[] value) { 358 GattService service = getService(); 359 if (service == null) return; 360 service.writeCharacteristic(clientIf, address, srvcType, srvcInstanceId, 361 srvcId.getUuid(), charInstanceId, 362 charId.getUuid(), writeType, authReq, 363 value); 364 } 365 366 public void readDescriptor(int clientIf, String address, int srvcType, 367 int srvcInstanceId, ParcelUuid srvcId, 368 int charInstanceId, ParcelUuid charId, 369 int descrInstanceId, ParcelUuid descrId, 370 int authReq) { 371 GattService service = getService(); 372 if (service == null) return; 373 service.readDescriptor(clientIf, address, srvcType, 374 srvcInstanceId, srvcId.getUuid(), 375 charInstanceId, charId.getUuid(), 376 descrInstanceId, descrId.getUuid(), 377 authReq); 378 } 379 380 public void writeDescriptor(int clientIf, String address, int srvcType, 381 int srvcInstanceId, ParcelUuid srvcId, 382 int charInstanceId, ParcelUuid charId, 383 int descrInstanceId, ParcelUuid descrId, 384 int writeType, int authReq, byte[] value) { 385 GattService service = getService(); 386 if (service == null) return; 387 service.writeDescriptor(clientIf, address, srvcType, 388 srvcInstanceId, srvcId.getUuid(), 389 charInstanceId, charId.getUuid(), 390 descrInstanceId, descrId.getUuid(), 391 writeType, authReq, value); 392 } 393 394 public void beginReliableWrite(int clientIf, String address) { 395 GattService service = getService(); 396 if (service == null) return; 397 service.beginReliableWrite(clientIf, address); 398 } 399 400 public void endReliableWrite(int clientIf, String address, boolean execute) { 401 GattService service = getService(); 402 if (service == null) return; 403 service.endReliableWrite(clientIf, address, execute); 404 } 405 406 public void registerForNotification(int clientIf, String address, int srvcType, 407 int srvcInstanceId, ParcelUuid srvcId, 408 int charInstanceId, ParcelUuid charId, 409 boolean enable) { 410 GattService service = getService(); 411 if (service == null) return; 412 service.registerForNotification(clientIf, address, srvcType, srvcInstanceId, 413 srvcId.getUuid(), charInstanceId, 414 charId.getUuid(), enable); 415 } 416 417 public void readRemoteRssi(int clientIf, String address) { 418 GattService service = getService(); 419 if (service == null) return; 420 service.readRemoteRssi(clientIf, address); 421 } 422 423 public void configureMTU(int clientIf, String address, int mtu) { 424 GattService service = getService(); 425 if (service == null) return; 426 service.configureMTU(clientIf, address, mtu); 427 } 428 429 public void connectionParameterUpdate(int clientIf, String address, 430 int connectionPriority) { 431 GattService service = getService(); 432 if (service == null) return; 433 service.connectionParameterUpdate(clientIf, address, connectionPriority); 434 } 435 436 public void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback) { 437 GattService service = getService(); 438 if (service == null) return; 439 service.registerServer(uuid.getUuid(), callback); 440 } 441 442 public void unregisterServer(int serverIf) { 443 GattService service = getService(); 444 if (service == null) return; 445 service.unregisterServer(serverIf); 446 } 447 448 public void serverConnect(int serverIf, String address, boolean isDirect, int transport) { 449 GattService service = getService(); 450 if (service == null) return; 451 service.serverConnect(serverIf, address, isDirect, transport); 452 } 453 454 public void serverDisconnect(int serverIf, String address) { 455 GattService service = getService(); 456 if (service == null) return; 457 service.serverDisconnect(serverIf, address); 458 } 459 460 public void beginServiceDeclaration(int serverIf, int srvcType, 461 int srvcInstanceId, int minHandles, 462 ParcelUuid srvcId, boolean advertisePreferred) { 463 GattService service = getService(); 464 if (service == null) return; 465 service.beginServiceDeclaration(serverIf, srvcType, srvcInstanceId, 466 minHandles, srvcId.getUuid(), advertisePreferred); 467 } 468 469 public void addIncludedService(int serverIf, int srvcType, 470 int srvcInstanceId, ParcelUuid srvcId) { 471 GattService service = getService(); 472 if (service == null) return; 473 service.addIncludedService(serverIf, srvcType, srvcInstanceId, 474 srvcId.getUuid()); 475 } 476 477 public void addCharacteristic(int serverIf, ParcelUuid charId, 478 int properties, int permissions) { 479 GattService service = getService(); 480 if (service == null) return; 481 service.addCharacteristic(serverIf, charId.getUuid(), properties, 482 permissions); 483 } 484 485 public void addDescriptor(int serverIf, ParcelUuid descId, 486 int permissions) { 487 GattService service = getService(); 488 if (service == null) return; 489 service.addDescriptor(serverIf, descId.getUuid(), permissions); 490 } 491 492 public void endServiceDeclaration(int serverIf) { 493 GattService service = getService(); 494 if (service == null) return; 495 service.endServiceDeclaration(serverIf); 496 } 497 498 public void removeService(int serverIf, int srvcType, 499 int srvcInstanceId, ParcelUuid srvcId) { 500 GattService service = getService(); 501 if (service == null) return; 502 service.removeService(serverIf, srvcType, srvcInstanceId, 503 srvcId.getUuid()); 504 } 505 506 public void clearServices(int serverIf) { 507 GattService service = getService(); 508 if (service == null) return; 509 service.clearServices(serverIf); 510 } 511 512 public void sendResponse(int serverIf, String address, int requestId, 513 int status, int offset, byte[] value) { 514 GattService service = getService(); 515 if (service == null) return; 516 service.sendResponse(serverIf, address, requestId, status, offset, value); 517 } 518 519 public void sendNotification(int serverIf, String address, int srvcType, 520 int srvcInstanceId, ParcelUuid srvcId, 521 int charInstanceId, ParcelUuid charId, 522 boolean confirm, byte[] value) { 523 GattService service = getService(); 524 if (service == null) return; 525 service.sendNotification(serverIf, address, srvcType, srvcInstanceId, 526 srvcId.getUuid(), charInstanceId, charId.getUuid(), confirm, value); 527 } 528 529 @Override 530 public void startMultiAdvertising(int clientIf, AdvertiseData advertiseData, 531 AdvertiseData scanResponse, AdvertiseSettings settings) { 532 GattService service = getService(); 533 if (service == null) return; 534 service.startMultiAdvertising(clientIf, advertiseData, scanResponse, settings); 535 } 536 537 @Override 538 public void stopMultiAdvertising(int clientIf) { 539 GattService service = getService(); 540 if (service == null) return; 541 service.stopMultiAdvertising(new AdvertiseClient(clientIf)); 542 } 543 }; 544 545 /************************************************************************** 546 * Callback functions - CLIENT 547 *************************************************************************/ 548 549 void onScanResult(String address, int rssi, byte[] adv_data) { 550 if (VDBG) Log.d(TAG, "onScanResult() - address=" + address 551 + ", rssi=" + rssi); 552 List<UUID> remoteUuids = parseUuids(adv_data); 553 for (ScanClient client : mScanManager.getRegularScanQueue()) { 554 if (client.uuids.length > 0) { 555 int matches = 0; 556 for (UUID search : client.uuids) { 557 for (UUID remote: remoteUuids) { 558 if (remote.equals(search)) { 559 ++matches; 560 break; // Only count 1st match in case of duplicates 561 } 562 } 563 } 564 565 if (matches < client.uuids.length) continue; 566 } 567 568 if (!client.isServer) { 569 ClientMap.App app = mClientMap.getById(client.clientIf); 570 if (app != null) { 571 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter() 572 .getRemoteDevice(address); 573 ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(adv_data), 574 rssi, SystemClock.elapsedRealtimeNanos()); 575 if (matchesFilters(client, result)) { 576 try { 577 ScanSettings settings = client.settings; 578 // framework detects the first match, hw signal is 579 // used to detect the onlost 580 // ToDo: make scanClient+result, 1 to many when hw 581 // support is available 582 if ((settings.getCallbackType() & 583 ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0) { 584 synchronized (mOnFoundResults) { 585 mOnFoundResults.put(client, result); 586 } 587 app.callback.onFoundOrLost(true, result); 588 } 589 if ((settings.getCallbackType() & 590 ScanSettings.CALLBACK_TYPE_ALL_MATCHES) != 0) { 591 app.callback.onScanResult(result); 592 } 593 } catch (RemoteException e) { 594 Log.e(TAG, "Exception: " + e); 595 mClientMap.remove(client.clientIf); 596 mScanManager.stopScan(client); 597 } 598 } 599 } 600 } else { 601 ServerMap.App app = mServerMap.getById(client.clientIf); 602 if (app != null) { 603 try { 604 app.callback.onScanResult(address, rssi, adv_data); 605 } catch (RemoteException e) { 606 Log.e(TAG, "Exception: " + e); 607 mServerMap.remove(client.clientIf); 608 mScanManager.stopScan(client); 609 } 610 } 611 } 612 } 613 } 614 615 // Check if a scan record matches a specific filters. 616 private boolean matchesFilters(ScanClient client, ScanResult scanResult) { 617 if (client.filters == null || client.filters.isEmpty()) { 618 return true; 619 } 620 for (ScanFilter filter : client.filters) { 621 if (filter.matches(scanResult)) { 622 return true; 623 } 624 } 625 return false; 626 } 627 628 void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb) 629 throws RemoteException { 630 UUID uuid = new UUID(uuidMsb, uuidLsb); 631 if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf); 632 ClientMap.App app = mClientMap.getByUuid(uuid); 633 if (app != null) { 634 app.id = clientIf; 635 app.linkToDeath(new ClientDeathRecipient(clientIf)); 636 app.callback.onClientRegistered(status, clientIf); 637 } 638 } 639 640 void onConnected(int clientIf, int connId, int status, String address) 641 throws RemoteException { 642 if (DBG) Log.d(TAG, "onConnected() - clientIf=" + clientIf 643 + ", connId=" + connId + ", address=" + address); 644 645 if (status == 0) mClientMap.addConnection(clientIf, connId, address); 646 ClientMap.App app = mClientMap.getById(clientIf); 647 if (app != null) { 648 app.callback.onClientConnectionState(status, clientIf, 649 (status==BluetoothGatt.GATT_SUCCESS), address); 650 } 651 } 652 653 void onDisconnected(int clientIf, int connId, int status, String address) 654 throws RemoteException { 655 if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf 656 + ", connId=" + connId + ", address=" + address); 657 658 mClientMap.removeConnection(clientIf, connId); 659 mSearchQueue.removeConnId(connId); 660 ClientMap.App app = mClientMap.getById(clientIf); 661 if (app != null) { 662 app.callback.onClientConnectionState(status, clientIf, false, address); 663 } 664 } 665 666 void onSearchCompleted(int connId, int status) throws RemoteException { 667 if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status); 668 // We got all services, now let's explore characteristics... 669 continueSearch(connId, status); 670 } 671 672 void onSearchResult(int connId, int srvcType, 673 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb) 674 throws RemoteException { 675 UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb); 676 String address = mClientMap.addressByConnId(connId); 677 678 if (VDBG) Log.d(TAG, "onSearchResult() - address=" + address + ", uuid=" + uuid); 679 680 mSearchQueue.add(connId, srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb); 681 682 ClientMap.App app = mClientMap.getByConnId(connId); 683 if (app != null) { 684 app.callback.onGetService(address, srvcType, srvcInstId, 685 new ParcelUuid(uuid)); 686 } 687 } 688 689 void onGetCharacteristic(int connId, int status, int srvcType, 690 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 691 int charInstId, long charUuidLsb, long charUuidMsb, 692 int charProp) throws RemoteException { 693 694 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 695 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 696 String address = mClientMap.addressByConnId(connId); 697 698 if (VDBG) Log.d(TAG, "onGetCharacteristic() - address=" + address 699 + ", status=" + status + ", charUuid=" + charUuid + ", prop=" + charProp); 700 701 if (status == 0) { 702 mSearchQueue.add(connId, srvcType, 703 srvcInstId, srvcUuidLsb, srvcUuidMsb, 704 charInstId, charUuidLsb, charUuidMsb); 705 706 ClientMap.App app = mClientMap.getByConnId(connId); 707 if (app != null) { 708 app.callback.onGetCharacteristic(address, srvcType, 709 srvcInstId, new ParcelUuid(srvcUuid), 710 charInstId, new ParcelUuid(charUuid), charProp); 711 } 712 713 // Get next characteristic in the current service 714 gattClientGetCharacteristicNative(connId, srvcType, 715 srvcInstId, srvcUuidLsb, srvcUuidMsb, 716 charInstId, charUuidLsb, charUuidMsb); 717 } else { 718 // Check for included services next 719 gattClientGetIncludedServiceNative(connId, 720 srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb, 721 0,0,0,0); 722 } 723 } 724 725 void onGetDescriptor(int connId, int status, int srvcType, 726 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 727 int charInstId, long charUuidLsb, long charUuidMsb, 728 int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException { 729 730 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 731 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 732 UUID descUuid = new UUID(descrUuidMsb, descrUuidLsb); 733 String address = mClientMap.addressByConnId(connId); 734 735 if (VDBG) Log.d(TAG, "onGetDescriptor() - address=" + address 736 + ", status=" + status + ", descUuid=" + descUuid); 737 738 if (status == 0) { 739 ClientMap.App app = mClientMap.getByConnId(connId); 740 if (app != null) { 741 app.callback.onGetDescriptor(address, srvcType, 742 srvcInstId, new ParcelUuid(srvcUuid), 743 charInstId, new ParcelUuid(charUuid), 744 descrInstId, new ParcelUuid(descUuid)); 745 } 746 747 // Get next descriptor for the current characteristic 748 gattClientGetDescriptorNative(connId, srvcType, 749 srvcInstId, srvcUuidLsb, srvcUuidMsb, 750 charInstId, charUuidLsb, charUuidMsb, 751 descrInstId, descrUuidLsb, descrUuidMsb); 752 } else { 753 // Explore the next service 754 continueSearch(connId, 0); 755 } 756 } 757 758 void onGetIncludedService(int connId, int status, int srvcType, 759 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, int inclSrvcType, 760 int inclSrvcInstId, long inclSrvcUuidLsb, long inclSrvcUuidMsb) 761 throws RemoteException { 762 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 763 UUID inclSrvcUuid = new UUID(inclSrvcUuidMsb, inclSrvcUuidLsb); 764 String address = mClientMap.addressByConnId(connId); 765 766 if (VDBG) Log.d(TAG, "onGetIncludedService() - address=" + address 767 + ", status=" + status + ", uuid=" + srvcUuid 768 + ", inclUuid=" + inclSrvcUuid); 769 770 if (status == 0) { 771 ClientMap.App app = mClientMap.getByConnId(connId); 772 if (app != null) { 773 app.callback.onGetIncludedService(address, 774 srvcType, srvcInstId, new ParcelUuid(srvcUuid), 775 inclSrvcType, inclSrvcInstId, new ParcelUuid(inclSrvcUuid)); 776 } 777 778 // Find additional included services 779 gattClientGetIncludedServiceNative(connId, 780 srvcType, srvcInstId, srvcUuidLsb, srvcUuidMsb, 781 inclSrvcType, inclSrvcInstId, inclSrvcUuidLsb, inclSrvcUuidMsb); 782 } else { 783 // Discover descriptors now 784 continueSearch(connId, 0); 785 } 786 } 787 788 void onRegisterForNotifications(int connId, int status, int registered, int srvcType, 789 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 790 int charInstId, long charUuidLsb, long charUuidMsb) { 791 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 792 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 793 String address = mClientMap.addressByConnId(connId); 794 795 if (DBG) Log.d(TAG, "onRegisterForNotifications() - address=" + address 796 + ", status=" + status + ", registered=" + registered 797 + ", charUuid=" + charUuid); 798 } 799 800 void onNotify(int connId, String address, int srvcType, 801 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 802 int charInstId, long charUuidLsb, long charUuidMsb, 803 boolean isNotify, byte[] data) throws RemoteException { 804 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 805 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 806 807 if (VDBG) Log.d(TAG, "onNotify() - address=" + address 808 + ", charUuid=" + charUuid + ", length=" + data.length); 809 810 ClientMap.App app = mClientMap.getByConnId(connId); 811 if (app != null) { 812 app.callback.onNotify(address, srvcType, 813 srvcInstId, new ParcelUuid(srvcUuid), 814 charInstId, new ParcelUuid(charUuid), 815 data); 816 } 817 } 818 819 void onReadCharacteristic(int connId, int status, int srvcType, 820 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 821 int charInstId, long charUuidLsb, long charUuidMsb, 822 int charType, byte[] data) throws RemoteException { 823 824 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 825 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 826 String address = mClientMap.addressByConnId(connId); 827 828 if (VDBG) Log.d(TAG, "onReadCharacteristic() - address=" + address 829 + ", status=" + status + ", length=" + data.length); 830 831 ClientMap.App app = mClientMap.getByConnId(connId); 832 if (app != null) { 833 app.callback.onCharacteristicRead(address, status, srvcType, 834 srvcInstId, new ParcelUuid(srvcUuid), 835 charInstId, new ParcelUuid(charUuid), data); 836 } 837 } 838 839 void onWriteCharacteristic(int connId, int status, int srvcType, 840 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 841 int charInstId, long charUuidLsb, long charUuidMsb) 842 throws RemoteException { 843 844 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 845 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 846 String address = mClientMap.addressByConnId(connId); 847 848 if (VDBG) Log.d(TAG, "onWriteCharacteristic() - address=" + address 849 + ", status=" + status); 850 851 ClientMap.App app = mClientMap.getByConnId(connId); 852 if (app == null) return; 853 854 if (!app.isCongested) { 855 app.callback.onCharacteristicWrite(address, status, srvcType, 856 srvcInstId, new ParcelUuid(srvcUuid), 857 charInstId, new ParcelUuid(charUuid)); 858 } else { 859 if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) { 860 status = BluetoothGatt.GATT_SUCCESS; 861 } 862 CallbackInfo callbackInfo = new CallbackInfo(address, status, srvcType, 863 srvcInstId, srvcUuid, charInstId, charUuid); 864 app.queueCallback(callbackInfo); 865 } 866 } 867 868 void onExecuteCompleted(int connId, int status) throws RemoteException { 869 String address = mClientMap.addressByConnId(connId); 870 if (VDBG) Log.d(TAG, "onExecuteCompleted() - address=" + address 871 + ", status=" + status); 872 873 ClientMap.App app = mClientMap.getByConnId(connId); 874 if (app != null) { 875 app.callback.onExecuteWrite(address, status); 876 } 877 } 878 879 void onReadDescriptor(int connId, int status, int srvcType, 880 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 881 int charInstId, long charUuidLsb, long charUuidMsb, 882 int descrInstId, long descrUuidLsb, long descrUuidMsb, 883 int charType, byte[] data) throws RemoteException { 884 885 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 886 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 887 UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb); 888 String address = mClientMap.addressByConnId(connId); 889 890 if (VDBG) Log.d(TAG, "onReadDescriptor() - address=" + address 891 + ", status=" + status + ", length=" + data.length); 892 893 ClientMap.App app = mClientMap.getByConnId(connId); 894 if (app != null) { 895 app.callback.onDescriptorRead(address, status, srvcType, 896 srvcInstId, new ParcelUuid(srvcUuid), 897 charInstId, new ParcelUuid(charUuid), 898 descrInstId, new ParcelUuid(descrUuid), data); 899 } 900 } 901 902 void onWriteDescriptor(int connId, int status, int srvcType, 903 int srvcInstId, long srvcUuidLsb, long srvcUuidMsb, 904 int charInstId, long charUuidLsb, long charUuidMsb, 905 int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException { 906 907 UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb); 908 UUID charUuid = new UUID(charUuidMsb, charUuidLsb); 909 UUID descrUuid = new UUID(descrUuidMsb, descrUuidLsb); 910 String address = mClientMap.addressByConnId(connId); 911 912 if (VDBG) Log.d(TAG, "onWriteDescriptor() - address=" + address 913 + ", status=" + status); 914 915 ClientMap.App app = mClientMap.getByConnId(connId); 916 if (app != null) { 917 app.callback.onDescriptorWrite(address, status, srvcType, 918 srvcInstId, new ParcelUuid(srvcUuid), 919 charInstId, new ParcelUuid(charUuid), 920 descrInstId, new ParcelUuid(descrUuid)); 921 } 922 } 923 924 void onReadRemoteRssi(int clientIf, String address, 925 int rssi, int status) throws RemoteException{ 926 if (DBG) Log.d(TAG, "onReadRemoteRssi() - clientIf=" + clientIf + " address=" + 927 address + ", rssi=" + rssi + ", status=" + status); 928 929 ClientMap.App app = mClientMap.getById(clientIf); 930 if (app != null) { 931 app.callback.onReadRemoteRssi(address, rssi, status); 932 } 933 } 934 935 void onScanFilterEnableDisabled(int action, int status, int clientIf) { 936 if (DBG) { 937 Log.d(TAG, "onScanFilterEnableDisabled() - clientIf=" + clientIf + ", status=" + status 938 + ", action=" + action); 939 } 940 mScanManager.callbackDone(clientIf, status); 941 } 942 943 void onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace) { 944 if (DBG) { 945 Log.d(TAG, "onScanFilterParamsConfigured() - clientIf=" + clientIf 946 + ", status=" + status + ", action=" + action 947 + ", availableSpace=" + availableSpace); 948 } 949 mScanManager.callbackDone(clientIf, status); 950 } 951 952 void onScanFilterConfig(int action, int status, int clientIf, int filterType, 953 int availableSpace) { 954 if (DBG) { 955 Log.d(TAG, "onScanFilterConfig() - clientIf=" + clientIf + ", action = " + action 956 + " status = " + status + ", filterType=" + filterType 957 + ", availableSpace=" + availableSpace); 958 } 959 960 mScanManager.callbackDone(clientIf, status); 961 } 962 963 void onBatchScanStorageConfigured(int status, int clientIf) { 964 if (DBG) { 965 Log.d(TAG, "onBatchScanStorageConfigured() - clientIf="+ clientIf + ", status=" + status); 966 } 967 mScanManager.callbackDone(clientIf, status); 968 } 969 970 // TODO: split into two different callbacks : onBatchScanStarted and onBatchScanStopped. 971 void onBatchScanStartStopped(int startStopAction, int status, int clientIf) { 972 if (DBG) { 973 Log.d(TAG, "onBatchScanStartStopped() - clientIf=" + clientIf 974 + ", status=" + status + ", startStopAction=" + startStopAction); 975 } 976 mScanManager.callbackDone(clientIf, status); 977 } 978 979 void onBatchScanReports(int status, int clientIf, int reportType, int numRecords, 980 byte[] recordData) throws RemoteException { 981 if (DBG) { 982 Log.d(TAG, "onBatchScanReports() - clientIf=" + clientIf + ", status=" + status 983 + ", reportType=" + reportType + ", numRecords=" + numRecords); 984 } 985 mScanManager.callbackDone(clientIf, status); 986 Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData); 987 if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) { 988 // We only support single client for truncated mode. 989 ClientMap.App app = mClientMap.getById(clientIf); 990 if (app == null) return; 991 app.callback.onBatchScanResults(new ArrayList<ScanResult>(results)); 992 } else { 993 for (ScanClient client : mScanManager.getFullBatchScanQueue()) { 994 // Deliver results for each client. 995 deliverBatchScan(client, results); 996 } 997 } 998 } 999 1000 // Check and deliver scan results for different scan clients. 1001 private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults) throws 1002 RemoteException { 1003 ClientMap.App app = mClientMap.getById(client.clientIf); 1004 if (app == null) return; 1005 if (client.filters == null || client.filters.isEmpty()) { 1006 app.callback.onBatchScanResults(new ArrayList<ScanResult>(allResults)); 1007 } 1008 // Reconstruct the scan results. 1009 List<ScanResult> results = new ArrayList<ScanResult>(); 1010 for (ScanResult scanResult : allResults) { 1011 if (matchesFilters(client, scanResult)) { 1012 results.add(scanResult); 1013 } 1014 } 1015 app.callback.onBatchScanResults(results); 1016 } 1017 1018 private Set<ScanResult> parseBatchScanResults(int numRecords, int reportType, 1019 byte[] batchRecord) { 1020 if (numRecords == 0) { 1021 return Collections.emptySet(); 1022 } 1023 if (DBG) Log.d(TAG, "current time is " + SystemClock.elapsedRealtimeNanos()); 1024 if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) { 1025 return parseTruncatedResults(numRecords, batchRecord); 1026 } else { 1027 return parseFullResults(numRecords, batchRecord); 1028 } 1029 } 1030 1031 private Set<ScanResult> parseTruncatedResults(int numRecords, byte[] batchRecord) { 1032 if (DBG) Log.d(TAG, "batch record " + Arrays.toString(batchRecord)); 1033 Set<ScanResult> results = new HashSet<ScanResult>(numRecords); 1034 long now = SystemClock.elapsedRealtimeNanos(); 1035 for (int i = 0; i < numRecords; ++i) { 1036 byte[] record = extractBytes(batchRecord, i * TRUNCATED_RESULT_SIZE, 1037 TRUNCATED_RESULT_SIZE); 1038 byte[] address = extractBytes(record, 0, 6); 1039 reverse(address); 1040 BluetoothDevice device = mAdapter.getRemoteDevice(address); 1041 int rssi = record[8]; 1042 long timestampNanos = now - parseTimestampNanos(extractBytes(record, 9, 2)); 1043 results.add(new ScanResult(device, ScanRecord.parseFromBytes(new byte[0]), 1044 rssi, timestampNanos)); 1045 } 1046 return results; 1047 } 1048 1049 @VisibleForTesting 1050 long parseTimestampNanos(byte[] data) { 1051 long timestampUnit = NumberUtils.littleEndianByteArrayToInt(data); 1052 // Timestamp is in every 50 ms. 1053 return TimeUnit.MILLISECONDS.toNanos(timestampUnit * 50); 1054 } 1055 1056 private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) { 1057 Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord)); 1058 Set<ScanResult> results = new HashSet<ScanResult>(numRecords); 1059 int position = 0; 1060 while (position < batchRecord.length) { 1061 byte[] address = extractBytes(batchRecord, position, 6); 1062 // TODO: remove temp hack. 1063 reverse(address); 1064 BluetoothDevice device = mAdapter.getRemoteDevice(address); 1065 position += 6; 1066 // Skip address type. 1067 position++; 1068 // Skip tx power level. 1069 position++; 1070 int rssi = batchRecord[position++]; 1071 long timestampNanos = parseTimestampNanos(extractBytes(batchRecord, position, 2)); 1072 position += 2; 1073 1074 // Combine advertise packet and scan response packet. 1075 int advertisePacketLen = batchRecord[position++]; 1076 byte[] advertiseBytes = extractBytes(batchRecord, position, advertisePacketLen); 1077 position += advertisePacketLen; 1078 int scanResponsePacketLen = batchRecord[position++]; 1079 byte[] scanResponseBytes = extractBytes(batchRecord, position, scanResponsePacketLen); 1080 position += scanResponsePacketLen; 1081 byte[] scanRecord = new byte[advertisePacketLen + scanResponsePacketLen]; 1082 System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen); 1083 System.arraycopy(scanResponseBytes, 0, scanRecord, 1084 advertisePacketLen, scanResponsePacketLen); 1085 Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord)); 1086 results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), 1087 rssi, timestampNanos)); 1088 } 1089 return results; 1090 } 1091 1092 // Reverse byte array. 1093 private void reverse(byte[] address) { 1094 int len = address.length; 1095 for (int i = 0; i < len / 2; ++i) { 1096 byte b = address[i]; 1097 address[i] = address[len - 1 - i]; 1098 address[len - 1 - i] = b; 1099 } 1100 } 1101 1102 // Helper method to extract bytes from byte array. 1103 private static byte[] extractBytes(byte[] scanRecord, int start, int length) { 1104 byte[] bytes = new byte[length]; 1105 System.arraycopy(scanRecord, start, bytes, 0, length); 1106 return bytes; 1107 } 1108 1109 void onBatchScanThresholdCrossed(int clientIf) { 1110 if (DBG) { 1111 Log.d(TAG, "onBatchScanThresholdCrossed() - clientIf=" + clientIf); 1112 } 1113 boolean isServer = false; 1114 flushPendingBatchResults(clientIf, isServer); 1115 } 1116 1117 void onTrackAdvFoundLost(int filterIndex, int addrType, String address, int advState, 1118 int clientIf) throws RemoteException { 1119 if (DBG) Log.d(TAG, "onClientAdvertiserFoundLost() - clientIf=" 1120 + clientIf + "address = " + address + "adv_state = " 1121 + advState + "client_if = " + clientIf); 1122 ClientMap.App app = mClientMap.getById(clientIf); 1123 if (app == null || app.callback == null) { 1124 Log.e(TAG, "app or callback is null"); 1125 return; 1126 } 1127 1128 // use hw signal for only onlost reporting 1129 if (advState != ADVT_STATE_ONLOST) { 1130 return; 1131 } 1132 1133 for (ScanClient client : mScanManager.getRegularScanQueue()) { 1134 if (client.clientIf == clientIf) { 1135 ScanSettings settings = client.settings; 1136 if ((settings.getCallbackType() & 1137 ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) { 1138 1139 while (!mOnFoundResults.isEmpty()) { 1140 ScanResult result = mOnFoundResults.get(client); 1141 app.callback.onFoundOrLost(false, result); 1142 synchronized (mOnFoundResults) { 1143 mOnFoundResults.remove(client); 1144 } 1145 } 1146 } 1147 } 1148 } 1149 } 1150 1151 // callback from AdvertiseManager for advertise status dispatch. 1152 void onMultipleAdvertiseCallback(int clientIf, int status, boolean isStart, 1153 AdvertiseSettings settings) throws RemoteException { 1154 ClientMap.App app = mClientMap.getById(clientIf); 1155 if (app == null || app.callback == null) { 1156 Log.e(TAG, "Advertise app or callback is null"); 1157 return; 1158 } 1159 app.callback.onMultiAdvertiseCallback(status, isStart, settings); 1160 } 1161 1162 void onConfigureMTU(int connId, int status, int mtu) throws RemoteException { 1163 String address = mClientMap.addressByConnId(connId); 1164 1165 if (DBG) Log.d(TAG, "onConfigureMTU() address=" + address + ", status=" 1166 + status + ", mtu=" + mtu); 1167 1168 ClientMap.App app = mClientMap.getByConnId(connId); 1169 if (app != null) { 1170 app.callback.onConfigureMTU(address, mtu, status); 1171 } 1172 } 1173 1174 // Callback for standard advertising instance. 1175 void onAdvertiseCallback(int status, int clientIf) { 1176 if (DBG) Log.d(TAG, "onAdvertiseCallback,- clientIf=" + clientIf + ", status=" + status); 1177 mAdvertiseManager.callbackDone(clientIf, status); 1178 } 1179 1180 // Followings are callbacks for Bluetooth LE Advertise operations. 1181 // Start advertising flow is 1182 // enable advertising instance -> onAdvertiseInstaceEnabled 1183 // -> set advertise data -> onAdvertiseDataSet 1184 // -> set scan response -> onAdvertiseDataSet 1185 1186 // Callback when advertise instance is enabled. 1187 void onAdvertiseInstanceEnabled(int status, int clientIf) { 1188 if (DBG) Log.d(TAG, "onAdvertiseInstanceEnabled() - " 1189 + "clientIf=" + clientIf + ", status=" + status); 1190 mAdvertiseManager.callbackDone(clientIf, status); 1191 } 1192 1193 // Not really used. 1194 void onAdvertiseDataUpdated(int status, int client_if) { 1195 if (DBG) Log.d(TAG, "onAdvertiseDataUpdated() - client_if=" + client_if 1196 + ", status=" + status); 1197 } 1198 1199 // Callback when advertise data or scan response is set. 1200 void onAdvertiseDataSet(int status, int clientIf) { 1201 if (DBG) Log.d(TAG, "onAdvertiseDataSet() - clientIf=" + clientIf 1202 + ", status=" + status); 1203 mAdvertiseManager.callbackDone(clientIf, status); 1204 } 1205 1206 // Callback when advertise instance is disabled 1207 void onAdvertiseInstanceDisabled(int status, int clientIf) throws RemoteException { 1208 if (DBG) Log.d(TAG, "onAdvertiseInstanceDisabled() - clientIf=" + clientIf 1209 + ", status=" + status); 1210 ClientMap.App app = mClientMap.getById(clientIf); 1211 if (app != null) { 1212 Log.d(TAG, "Client app is not null!"); 1213 boolean isStart = false; 1214 if (status == 0) { 1215 app.callback.onMultiAdvertiseCallback(AdvertiseCallback.ADVERTISE_SUCCESS, 1216 isStart, null); 1217 } else { 1218 app.callback.onMultiAdvertiseCallback( 1219 AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR, isStart, null); 1220 } 1221 } 1222 } 1223 1224 void onClientCongestion(int connId, boolean congested) throws RemoteException { 1225 if (VDBG) Log.d(TAG, "onClientCongestion() - connId=" + connId + ", congested=" + congested); 1226 1227 ClientMap.App app = mClientMap.getByConnId(connId); 1228 1229 if (app != null) { 1230 app.isCongested = congested; 1231 while(!app.isCongested) { 1232 CallbackInfo callbackInfo = app.popQueuedCallback(); 1233 if (callbackInfo == null) return; 1234 app.callback.onCharacteristicWrite(callbackInfo.address, 1235 callbackInfo.status, callbackInfo.srvcType, 1236 callbackInfo.srvcInstId, new ParcelUuid(callbackInfo.srvcUuid), 1237 callbackInfo.charInstId, new ParcelUuid(callbackInfo.charUuid)); 1238 } 1239 } 1240 } 1241 1242 /************************************************************************** 1243 * GATT Service functions - Shared CLIENT/SERVER 1244 *************************************************************************/ 1245 1246 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 1247 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1248 1249 final int DEVICE_TYPE_BREDR = 0x1; 1250 1251 Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice, 1252 Integer>(); 1253 1254 // Add paired LE devices 1255 1256 Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); 1257 for (BluetoothDevice device : bondedDevices) { 1258 if (getDeviceType(device) != DEVICE_TYPE_BREDR) { 1259 deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED); 1260 } 1261 } 1262 1263 // Add connected deviceStates 1264 1265 Set<String> connectedDevices = new HashSet<String>(); 1266 connectedDevices.addAll(mClientMap.getConnectedDevices()); 1267 connectedDevices.addAll(mServerMap.getConnectedDevices()); 1268 1269 for (String address : connectedDevices ) { 1270 BluetoothDevice device = mAdapter.getRemoteDevice(address); 1271 if (device != null) { 1272 deviceStates.put(device, BluetoothProfile.STATE_CONNECTED); 1273 } 1274 } 1275 1276 // Create matching device sub-set 1277 1278 List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); 1279 1280 for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) { 1281 for(int state : states) { 1282 if (entry.getValue() == state) { 1283 deviceList.add(entry.getKey()); 1284 } 1285 } 1286 } 1287 1288 return deviceList; 1289 } 1290 1291 void startScan(int appIf, boolean isServer, ScanSettings settings, 1292 List<ScanFilter> filters, List<List<ResultStorageDescriptor>> storages) { 1293 if (DBG) Log.d(TAG, "start scan with filters"); 1294 enforceAdminPermission(); 1295 if (needsPrivilegedPermissionForScan(settings)) { 1296 enforcePrivilegedPermission(); 1297 } 1298 mScanManager.startScan(new ScanClient(appIf, isServer, settings, filters, storages)); 1299 } 1300 1301 void flushPendingBatchResults(int clientIf, boolean isServer) { 1302 if (DBG) Log.d(TAG, "flushPendingBatchResults - clientIf=" + clientIf + 1303 ", isServer=" + isServer); 1304 mScanManager.flushBatchScanResults(new ScanClient(clientIf, isServer)); 1305 } 1306 1307 void stopScan(ScanClient client) { 1308 enforceAdminPermission(); 1309 int scanQueueSize = mScanManager.getBatchScanQueue().size() + 1310 mScanManager.getRegularScanQueue().size(); 1311 if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize); 1312 mScanManager.stopScan(client); 1313 } 1314 1315 /************************************************************************** 1316 * GATT Service functions - CLIENT 1317 *************************************************************************/ 1318 1319 void registerClient(UUID uuid, IBluetoothGattCallback callback) { 1320 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1321 1322 if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid); 1323 mClientMap.add(uuid, callback); 1324 gattClientRegisterAppNative(uuid.getLeastSignificantBits(), 1325 uuid.getMostSignificantBits()); 1326 } 1327 1328 void unregisterClient(int clientIf) { 1329 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1330 1331 if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf); 1332 mClientMap.remove(clientIf); 1333 gattClientUnregisterAppNative(clientIf); 1334 } 1335 1336 void clientConnect(int clientIf, String address, boolean isDirect, int transport) { 1337 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1338 1339 if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect); 1340 gattClientConnectNative(clientIf, address, isDirect, transport); 1341 } 1342 1343 void clientDisconnect(int clientIf, String address) { 1344 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1345 1346 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1347 if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId); 1348 1349 gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0); 1350 } 1351 1352 void startMultiAdvertising(int clientIf, AdvertiseData advertiseData, 1353 AdvertiseData scanResponse, AdvertiseSettings settings) { 1354 enforceAdminPermission(); 1355 mAdvertiseManager.startAdvertising(new AdvertiseClient(clientIf, settings, advertiseData, 1356 scanResponse)); 1357 } 1358 1359 void stopMultiAdvertising(AdvertiseClient client) { 1360 enforceAdminPermission(); 1361 mAdvertiseManager.stopAdvertising(client); 1362 } 1363 1364 1365 synchronized List<ParcelUuid> getRegisteredServiceUuids() { 1366 Utils.enforceAdminPermission(this); 1367 List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>(); 1368 for (HandleMap.Entry entry : mHandleMap.mEntries) { 1369 serviceUuids.add(new ParcelUuid(entry.uuid)); 1370 } 1371 return serviceUuids; 1372 } 1373 1374 List<String> getConnectedDevices() { 1375 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1376 1377 Set<String> connectedDevAddress = new HashSet<String>(); 1378 connectedDevAddress.addAll(mClientMap.getConnectedDevices()); 1379 connectedDevAddress.addAll(mServerMap.getConnectedDevices()); 1380 List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress); 1381 return connectedDeviceList; 1382 } 1383 1384 void refreshDevice(int clientIf, String address) { 1385 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1386 1387 if (DBG) Log.d(TAG, "refreshDevice() - address=" + address); 1388 gattClientRefreshNative(clientIf, address); 1389 } 1390 1391 void discoverServices(int clientIf, String address) { 1392 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1393 1394 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1395 if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId); 1396 1397 if (connId != null) 1398 gattClientSearchServiceNative(connId, true, 0, 0); 1399 else 1400 Log.e(TAG, "discoverServices() - No connection for " + address + "..."); 1401 } 1402 1403 void readCharacteristic(int clientIf, String address, int srvcType, 1404 int srvcInstanceId, UUID srvcUuid, 1405 int charInstanceId, UUID charUuid, int authReq) { 1406 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1407 1408 if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address); 1409 1410 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1411 if (connId != null) 1412 gattClientReadCharacteristicNative(connId, srvcType, 1413 srvcInstanceId, srvcUuid.getLeastSignificantBits(), 1414 srvcUuid.getMostSignificantBits(), charInstanceId, 1415 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 1416 authReq); 1417 else 1418 Log.e(TAG, "readCharacteristic() - No connection for " + address + "..."); 1419 } 1420 1421 void writeCharacteristic(int clientIf, String address, int srvcType, 1422 int srvcInstanceId, UUID srvcUuid, 1423 int charInstanceId, UUID charUuid, int writeType, 1424 int authReq, byte[] value) { 1425 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1426 1427 if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address); 1428 1429 if (mReliableQueue.contains(address)) writeType = 3; // Prepared write 1430 1431 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1432 if (connId != null) 1433 gattClientWriteCharacteristicNative(connId, srvcType, 1434 srvcInstanceId, srvcUuid.getLeastSignificantBits(), 1435 srvcUuid.getMostSignificantBits(), charInstanceId, 1436 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 1437 writeType, authReq, value); 1438 else 1439 Log.e(TAG, "writeCharacteristic() - No connection for " + address + "..."); 1440 } 1441 1442 void readDescriptor(int clientIf, String address, int srvcType, 1443 int srvcInstanceId, UUID srvcUuid, 1444 int charInstanceId, UUID charUuid, 1445 int descrInstanceId, UUID descrUuid, 1446 int authReq) { 1447 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1448 1449 if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address); 1450 1451 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1452 if (connId != null) 1453 gattClientReadDescriptorNative(connId, srvcType, 1454 srvcInstanceId, 1455 srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(), 1456 charInstanceId, 1457 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 1458 descrInstanceId, 1459 descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(), 1460 authReq); 1461 else 1462 Log.e(TAG, "readDescriptor() - No connection for " + address + "..."); 1463 }; 1464 1465 void writeDescriptor(int clientIf, String address, int srvcType, 1466 int srvcInstanceId, UUID srvcUuid, 1467 int charInstanceId, UUID charUuid, 1468 int descrInstanceId, UUID descrUuid, 1469 int writeType, int authReq, byte[] value) { 1470 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1471 1472 if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address); 1473 1474 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1475 if (connId != null) 1476 gattClientWriteDescriptorNative(connId, srvcType, 1477 srvcInstanceId, 1478 srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(), 1479 charInstanceId, 1480 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 1481 descrInstanceId, 1482 descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(), 1483 writeType, authReq, value); 1484 else 1485 Log.e(TAG, "writeDescriptor() - No connection for " + address + "..."); 1486 } 1487 1488 void beginReliableWrite(int clientIf, String address) { 1489 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1490 1491 if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address); 1492 mReliableQueue.add(address); 1493 } 1494 1495 void endReliableWrite(int clientIf, String address, boolean execute) { 1496 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1497 1498 if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address 1499 + " execute: " + execute); 1500 mReliableQueue.remove(address); 1501 1502 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1503 if (connId != null) gattClientExecuteWriteNative(connId, execute); 1504 } 1505 1506 void registerForNotification(int clientIf, String address, int srvcType, 1507 int srvcInstanceId, UUID srvcUuid, 1508 int charInstanceId, UUID charUuid, 1509 boolean enable) { 1510 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1511 1512 if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable); 1513 1514 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1515 if (connId != null) { 1516 gattClientRegisterForNotificationsNative(clientIf, address, 1517 srvcType, srvcInstanceId, srvcUuid.getLeastSignificantBits(), 1518 srvcUuid.getMostSignificantBits(), charInstanceId, 1519 charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(), 1520 enable); 1521 } else { 1522 Log.e(TAG, "registerForNotification() - No connection for " + address + "..."); 1523 } 1524 } 1525 1526 void readRemoteRssi(int clientIf, String address) { 1527 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1528 1529 if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address); 1530 gattClientReadRemoteRssiNative(clientIf, address); 1531 } 1532 1533 void configureMTU(int clientIf, String address, int mtu) { 1534 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1535 1536 if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu); 1537 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1538 if (connId != null) { 1539 gattClientConfigureMTUNative(connId, mtu); 1540 } else { 1541 Log.e(TAG, "configureMTU() - No connection for " + address + "..."); 1542 } 1543 } 1544 1545 void connectionParameterUpdate(int clientIf, String address, int connectionPriority) { 1546 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1547 1548 // Default spec recommended interval is 30->50 ms 1549 int minInterval = 24; // 24 * 1.25ms = 30ms 1550 int maxInterval = 40; // 40 * 1.25ms = 50ms 1551 1552 // Slave latency 1553 int latency = 0; 1554 1555 // Link supervision timeout is measured in N * 10ms 1556 int timeout = 2000; // 20s 1557 1558 switch (connectionPriority) 1559 { 1560 case BluetoothGatt.CONNECTION_PRIORITY_HIGH: 1561 minInterval = 6; // 7.5ms 1562 maxInterval = 8; // 10ms 1563 break; 1564 1565 case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER: 1566 minInterval = 80; // 100ms 1567 maxInterval = 100; // 125ms 1568 latency = 2; 1569 break; 1570 } 1571 1572 if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address 1573 + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval); 1574 gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval, 1575 latency, timeout); 1576 } 1577 1578 /************************************************************************** 1579 * Callback functions - SERVER 1580 *************************************************************************/ 1581 1582 void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb) 1583 throws RemoteException { 1584 1585 UUID uuid = new UUID(uuidMsb, uuidLsb); 1586 if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf); 1587 ServerMap.App app = mServerMap.getByUuid(uuid); 1588 if (app != null) { 1589 app.id = serverIf; 1590 app.linkToDeath(new ServerDeathRecipient(serverIf)); 1591 app.callback.onServerRegistered(status, serverIf); 1592 } 1593 } 1594 1595 void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId, 1596 long srvcUuidLsb, long srvcUuidMsb, int srvcHandle) 1597 throws RemoteException { 1598 UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb); 1599 if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status 1600 + ", handle=" + srvcHandle); 1601 if (status == 0) { 1602 mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId, 1603 mAdvertisingServiceUuids.remove(uuid)); 1604 } 1605 1606 continueServiceDeclaration(serverIf, status, srvcHandle); 1607 } 1608 1609 void onIncludedServiceAdded(int status, int serverIf, int srvcHandle, 1610 int includedSrvcHandle) throws RemoteException { 1611 if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status 1612 + ", service=" + srvcHandle + ", included=" + includedSrvcHandle); 1613 continueServiceDeclaration(serverIf, status, srvcHandle); 1614 } 1615 1616 void onCharacteristicAdded(int status, int serverIf, 1617 long charUuidLsb, long charUuidMsb, 1618 int srvcHandle, int charHandle) 1619 throws RemoteException { 1620 UUID uuid = new UUID(charUuidMsb, charUuidLsb); 1621 if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status 1622 + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle); 1623 if (status == 0) 1624 mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle); 1625 continueServiceDeclaration(serverIf, status, srvcHandle); 1626 } 1627 1628 void onDescriptorAdded(int status, int serverIf, 1629 long descrUuidLsb, long descrUuidMsb, 1630 int srvcHandle, int descrHandle) 1631 throws RemoteException { 1632 UUID uuid = new UUID(descrUuidMsb, descrUuidLsb); 1633 if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status 1634 + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle); 1635 if (status == 0) 1636 mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle); 1637 continueServiceDeclaration(serverIf, status, srvcHandle); 1638 } 1639 1640 void onServiceStarted(int status, int serverIf, int srvcHandle) 1641 throws RemoteException { 1642 if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle 1643 + ", status=" + status); 1644 if (status == 0) 1645 mHandleMap.setStarted(serverIf, srvcHandle, true); 1646 } 1647 1648 void onServiceStopped(int status, int serverIf, int srvcHandle) 1649 throws RemoteException { 1650 if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle 1651 + ", status=" + status); 1652 if (status == 0) 1653 mHandleMap.setStarted(serverIf, srvcHandle, false); 1654 stopNextService(serverIf, status); 1655 } 1656 1657 void onServiceDeleted(int status, int serverIf, int srvcHandle) { 1658 if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle 1659 + ", status=" + status); 1660 mHandleMap.deleteService(serverIf, srvcHandle); 1661 } 1662 1663 void onClientConnected(String address, boolean connected, int connId, int serverIf) 1664 throws RemoteException { 1665 1666 if (DBG) Log.d(TAG, "onConnected() connId=" + connId 1667 + ", address=" + address + ", connected=" + connected); 1668 1669 ServerMap.App app = mServerMap.getById(serverIf); 1670 if (app == null) return; 1671 1672 if (connected) { 1673 mServerMap.addConnection(serverIf, connId, address); 1674 } else { 1675 mServerMap.removeConnection(serverIf, connId); 1676 } 1677 1678 app.callback.onServerConnectionState((byte)0, serverIf, connected, address); 1679 } 1680 1681 void onAttributeRead(String address, int connId, int transId, 1682 int attrHandle, int offset, boolean isLong) 1683 throws RemoteException { 1684 if (VDBG) Log.d(TAG, "onAttributeRead() connId=" + connId 1685 + ", address=" + address + ", handle=" + attrHandle 1686 + ", requestId=" + transId + ", offset=" + offset); 1687 1688 HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle); 1689 if (entry == null) return; 1690 1691 mHandleMap.addRequest(transId, attrHandle); 1692 1693 ServerMap.App app = mServerMap.getById(entry.serverIf); 1694 if (app == null) return; 1695 1696 switch(entry.type) { 1697 case HandleMap.TYPE_CHARACTERISTIC: 1698 { 1699 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1700 app.callback.onCharacteristicReadRequest(address, transId, offset, isLong, 1701 serviceEntry.serviceType, serviceEntry.instance, 1702 new ParcelUuid(serviceEntry.uuid), entry.instance, 1703 new ParcelUuid(entry.uuid)); 1704 break; 1705 } 1706 1707 case HandleMap.TYPE_DESCRIPTOR: 1708 { 1709 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1710 HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle); 1711 app.callback.onDescriptorReadRequest(address, transId, offset, isLong, 1712 serviceEntry.serviceType, serviceEntry.instance, 1713 new ParcelUuid(serviceEntry.uuid), charEntry.instance, 1714 new ParcelUuid(charEntry.uuid), 1715 new ParcelUuid(entry.uuid)); 1716 break; 1717 } 1718 1719 default: 1720 Log.e(TAG, "onAttributeRead() - Requested unknown attribute type."); 1721 break; 1722 } 1723 } 1724 1725 void onAttributeWrite(String address, int connId, int transId, 1726 int attrHandle, int offset, int length, 1727 boolean needRsp, boolean isPrep, 1728 byte[] data) 1729 throws RemoteException { 1730 if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId 1731 + ", address=" + address + ", handle=" + attrHandle 1732 + ", requestId=" + transId + ", isPrep=" + isPrep 1733 + ", offset=" + offset); 1734 1735 HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle); 1736 if (entry == null) return; 1737 1738 mHandleMap.addRequest(transId, attrHandle); 1739 1740 ServerMap.App app = mServerMap.getById(entry.serverIf); 1741 if (app == null) return; 1742 1743 switch(entry.type) { 1744 case HandleMap.TYPE_CHARACTERISTIC: 1745 { 1746 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1747 app.callback.onCharacteristicWriteRequest(address, transId, 1748 offset, length, isPrep, needRsp, 1749 serviceEntry.serviceType, serviceEntry.instance, 1750 new ParcelUuid(serviceEntry.uuid), entry.instance, 1751 new ParcelUuid(entry.uuid), data); 1752 break; 1753 } 1754 1755 case HandleMap.TYPE_DESCRIPTOR: 1756 { 1757 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1758 HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle); 1759 app.callback.onDescriptorWriteRequest(address, transId, 1760 offset, length, isPrep, needRsp, 1761 serviceEntry.serviceType, serviceEntry.instance, 1762 new ParcelUuid(serviceEntry.uuid), charEntry.instance, 1763 new ParcelUuid(charEntry.uuid), 1764 new ParcelUuid(entry.uuid), data); 1765 break; 1766 } 1767 1768 default: 1769 Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type."); 1770 break; 1771 } 1772 } 1773 1774 void onExecuteWrite(String address, int connId, int transId, int execWrite) 1775 throws RemoteException { 1776 if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId 1777 + ", address=" + address + ", transId=" + transId); 1778 1779 ServerMap.App app = mServerMap.getByConnId(connId); 1780 if (app == null) return; 1781 1782 app.callback.onExecuteWrite(address, transId, execWrite == 1); 1783 } 1784 1785 void onResponseSendCompleted(int status, int attrHandle) { 1786 if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle); 1787 } 1788 1789 void onNotificationSent(int connId, int status) throws RemoteException { 1790 if (VDBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status); 1791 1792 String address = mServerMap.addressByConnId(connId); 1793 if (address == null) return; 1794 1795 ServerMap.App app = mServerMap.getByConnId(connId); 1796 if (app == null) return; 1797 1798 if (!app.isCongested) { 1799 app.callback.onNotificationSent(address, status); 1800 } else { 1801 if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) { 1802 status = BluetoothGatt.GATT_SUCCESS; 1803 } 1804 app.queueCallback(new CallbackInfo(address, status)); 1805 } 1806 } 1807 1808 void onServerCongestion(int connId, boolean congested) throws RemoteException { 1809 if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested); 1810 1811 ServerMap.App app = mServerMap.getByConnId(connId); 1812 if (app == null) return; 1813 1814 app.isCongested = congested; 1815 while(!app.isCongested) { 1816 CallbackInfo callbackInfo = app.popQueuedCallback(); 1817 if (callbackInfo == null) return; 1818 app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status); 1819 } 1820 } 1821 1822 void onMtuChanged(int connId, int mtu) throws RemoteException { 1823 if (DBG) Log.d(TAG, "onMtuChanged() - connId=" + connId + ", mtu=" + mtu); 1824 1825 String address = mServerMap.addressByConnId(connId); 1826 if (address == null) return; 1827 1828 ServerMap.App app = mServerMap.getByConnId(connId); 1829 if (app == null) return; 1830 1831 app.callback.onMtuChanged(address, mtu); 1832 } 1833 1834 /************************************************************************** 1835 * GATT Service functions - SERVER 1836 *************************************************************************/ 1837 1838 void registerServer(UUID uuid, IBluetoothGattServerCallback callback) { 1839 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1840 1841 if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid); 1842 mServerMap.add(uuid, callback); 1843 gattServerRegisterAppNative(uuid.getLeastSignificantBits(), 1844 uuid.getMostSignificantBits()); 1845 } 1846 1847 void unregisterServer(int serverIf) { 1848 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1849 1850 if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf); 1851 1852 deleteServices(serverIf); 1853 1854 mServerMap.remove(serverIf); 1855 gattServerUnregisterAppNative(serverIf); 1856 } 1857 1858 void serverConnect(int serverIf, String address, boolean isDirect, int transport) { 1859 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1860 1861 if (DBG) Log.d(TAG, "serverConnect() - address=" + address); 1862 gattServerConnectNative(serverIf, address, isDirect,transport); 1863 } 1864 1865 void serverDisconnect(int serverIf, String address) { 1866 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1867 1868 Integer connId = mServerMap.connIdByAddress(serverIf, address); 1869 if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId); 1870 1871 gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0); 1872 } 1873 1874 void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId, 1875 int minHandles, UUID srvcUuid, boolean advertisePreferred) { 1876 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1877 1878 if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid); 1879 ServiceDeclaration serviceDeclaration = addDeclaration(); 1880 serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles, 1881 advertisePreferred); 1882 } 1883 1884 void addIncludedService(int serverIf, int srvcType, int srvcInstanceId, 1885 UUID srvcUuid) { 1886 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1887 1888 if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid); 1889 getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId); 1890 } 1891 1892 void addCharacteristic(int serverIf, UUID charUuid, int properties, 1893 int permissions) { 1894 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1895 1896 if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid); 1897 getActiveDeclaration().addCharacteristic(charUuid, properties, permissions); 1898 } 1899 1900 void addDescriptor(int serverIf, UUID descUuid, int permissions) { 1901 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1902 1903 if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid); 1904 getActiveDeclaration().addDescriptor(descUuid, permissions); 1905 } 1906 1907 void endServiceDeclaration(int serverIf) { 1908 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1909 1910 if (DBG) Log.d(TAG, "endServiceDeclaration()"); 1911 1912 if (getActiveDeclaration() == getPendingDeclaration()) { 1913 try { 1914 continueServiceDeclaration(serverIf, (byte)0, 0); 1915 } catch (RemoteException e) { 1916 Log.e(TAG,""+e); 1917 } 1918 } 1919 } 1920 1921 void removeService(int serverIf, int srvcType, 1922 int srvcInstanceId, UUID srvcUuid) { 1923 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1924 1925 if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid); 1926 1927 int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId); 1928 if (srvcHandle == 0) return; 1929 gattServerDeleteServiceNative(serverIf, srvcHandle); 1930 } 1931 1932 void clearServices(int serverIf) { 1933 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1934 1935 if (DBG) Log.d(TAG, "clearServices()"); 1936 deleteServices(serverIf); 1937 } 1938 1939 void sendResponse(int serverIf, String address, int requestId, 1940 int status, int offset, byte[] value) { 1941 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1942 1943 if (VDBG) Log.d(TAG, "sendResponse() - address=" + address); 1944 1945 int handle = 0; 1946 HandleMap.Entry entry = mHandleMap.getByRequestId(requestId); 1947 if (entry != null) handle = entry.handle; 1948 1949 int connId = mServerMap.connIdByAddress(serverIf, address); 1950 gattServerSendResponseNative(serverIf, connId, requestId, (byte)status, 1951 handle, offset, value, (byte)0); 1952 mHandleMap.deleteRequest(requestId); 1953 } 1954 1955 void sendNotification(int serverIf, String address, int srvcType, 1956 int srvcInstanceId, UUID srvcUuid, 1957 int charInstanceId, UUID charUuid, 1958 boolean confirm, byte[] value) { 1959 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1960 1961 if (VDBG) Log.d(TAG, "sendNotification() - address=" + address); 1962 1963 int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId); 1964 if (srvcHandle == 0) return; 1965 1966 int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId); 1967 if (charHandle == 0) return; 1968 1969 int connId = mServerMap.connIdByAddress(serverIf, address); 1970 if (connId == 0) return; 1971 1972 if (confirm) { 1973 gattServerSendIndicationNative(serverIf, charHandle, connId, value); 1974 } else { 1975 gattServerSendNotificationNative(serverIf, charHandle, connId, value); 1976 } 1977 } 1978 1979 1980 /************************************************************************** 1981 * Private functions 1982 *************************************************************************/ 1983 1984 private int getDeviceType(BluetoothDevice device) { 1985 int type = gattClientGetDeviceTypeNative(device.getAddress()); 1986 if (DBG) Log.d(TAG, "getDeviceType() - device=" + device 1987 + ", type=" + type); 1988 return type; 1989 } 1990 1991 private void enforceAdminPermission() { 1992 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 1993 } 1994 1995 private boolean needsPrivilegedPermissionForScan(ScanSettings settings) { 1996 // Regular scan, no special permission. 1997 if (settings == null) { 1998 return false; 1999 } 2000 // Hidden API for onLost/onFound 2001 if (settings.getCallbackType() != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { 2002 return true; 2003 } 2004 // Regular scan, no special permission. 2005 if (settings.getReportDelayMillis() == 0) { 2006 return false; 2007 } 2008 // Batch scan, truncated mode needs permission. 2009 return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED; 2010 } 2011 2012 // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be 2013 // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission. 2014 private void enforcePrivilegedPermission() { 2015 enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, 2016 "Need BLUETOOTH_PRIVILEGED permission"); 2017 } 2018 2019 private void continueSearch(int connId, int status) throws RemoteException { 2020 if (status == 0 && !mSearchQueue.isEmpty()) { 2021 SearchQueue.Entry svc = mSearchQueue.pop(); 2022 2023 if (svc.charUuidLsb == 0) { 2024 // Characteristic is up next 2025 gattClientGetCharacteristicNative(svc.connId, svc.srvcType, 2026 svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0); 2027 } else { 2028 // Descriptor is up next 2029 gattClientGetDescriptorNative(svc.connId, svc.srvcType, 2030 svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 2031 svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0); 2032 } 2033 } else { 2034 ClientMap.App app = mClientMap.getByConnId(connId); 2035 if (app != null) { 2036 app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status); 2037 } 2038 } 2039 } 2040 2041 private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException { 2042 if (mServiceDeclarations.size() == 0) return; 2043 if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle); 2044 2045 boolean finished = false; 2046 2047 ServiceDeclaration.Entry entry = null; 2048 if (status == 0) 2049 entry = getPendingDeclaration().getNext(); 2050 2051 if (entry != null) { 2052 if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type=" 2053 + entry.type); 2054 switch(entry.type) { 2055 case ServiceDeclaration.TYPE_SERVICE: 2056 if (entry.advertisePreferred) { 2057 mAdvertisingServiceUuids.add(entry.uuid); 2058 } 2059 gattServerAddServiceNative(serverIf, entry.serviceType, 2060 entry.instance, 2061 entry.uuid.getLeastSignificantBits(), 2062 entry.uuid.getMostSignificantBits(), 2063 getPendingDeclaration().getNumHandles()); 2064 break; 2065 2066 case ServiceDeclaration.TYPE_CHARACTERISTIC: 2067 gattServerAddCharacteristicNative(serverIf, srvcHandle, 2068 entry.uuid.getLeastSignificantBits(), 2069 entry.uuid.getMostSignificantBits(), 2070 entry.properties, entry.permissions); 2071 break; 2072 2073 case ServiceDeclaration.TYPE_DESCRIPTOR: 2074 gattServerAddDescriptorNative(serverIf, srvcHandle, 2075 entry.uuid.getLeastSignificantBits(), 2076 entry.uuid.getMostSignificantBits(), 2077 entry.permissions); 2078 break; 2079 2080 case ServiceDeclaration.TYPE_INCLUDED_SERVICE: 2081 { 2082 int inclSrvc = mHandleMap.getServiceHandle(entry.uuid, 2083 entry.serviceType, entry.instance); 2084 if (inclSrvc != 0) { 2085 gattServerAddIncludedServiceNative(serverIf, srvcHandle, 2086 inclSrvc); 2087 } else { 2088 finished = true; 2089 } 2090 break; 2091 } 2092 } 2093 } else { 2094 gattServerStartServiceNative(serverIf, srvcHandle, 2095 (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE); 2096 finished = true; 2097 } 2098 2099 if (finished) { 2100 if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed."); 2101 ServerMap.App app = mServerMap.getById(serverIf); 2102 if (app != null) { 2103 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle); 2104 2105 if (serviceEntry != null) { 2106 app.callback.onServiceAdded(status, serviceEntry.serviceType, 2107 serviceEntry.instance, new ParcelUuid(serviceEntry.uuid)); 2108 } else { 2109 app.callback.onServiceAdded(status, 0, 0, null); 2110 } 2111 } 2112 removePendingDeclaration(); 2113 2114 if (getPendingDeclaration() != null) { 2115 continueServiceDeclaration(serverIf, (byte)0, 0); 2116 } 2117 } 2118 } 2119 2120 private void stopNextService(int serverIf, int status) throws RemoteException { 2121 if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf 2122 + ", status=" + status); 2123 2124 if (status == 0) { 2125 List<HandleMap.Entry> entries = mHandleMap.getEntries(); 2126 for(HandleMap.Entry entry : entries) { 2127 if (entry.type != HandleMap.TYPE_SERVICE || 2128 entry.serverIf != serverIf || 2129 entry.started == false) 2130 continue; 2131 2132 gattServerStopServiceNative(serverIf, entry.handle); 2133 return; 2134 } 2135 } 2136 } 2137 2138 private void deleteServices(int serverIf) { 2139 if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf); 2140 2141 /* 2142 * Figure out which handles to delete. 2143 * The handles are copied into a new list to avoid race conditions. 2144 */ 2145 List<Integer> handleList = new ArrayList<Integer>(); 2146 List<HandleMap.Entry> entries = mHandleMap.getEntries(); 2147 for(HandleMap.Entry entry : entries) { 2148 if (entry.type != HandleMap.TYPE_SERVICE || 2149 entry.serverIf != serverIf) 2150 continue; 2151 handleList.add(entry.handle); 2152 } 2153 2154 /* Now actually delete the services.... */ 2155 for(Integer handle : handleList) { 2156 gattServerDeleteServiceNative(serverIf, handle); 2157 } 2158 } 2159 2160 private List<UUID> parseUuids(byte[] adv_data) { 2161 List<UUID> uuids = new ArrayList<UUID>(); 2162 2163 int offset = 0; 2164 while(offset < (adv_data.length-2)) { 2165 int len = adv_data[offset++]; 2166 if (len == 0) break; 2167 2168 int type = adv_data[offset++]; 2169 switch (type) { 2170 case 0x02: // Partial list of 16-bit UUIDs 2171 case 0x03: // Complete list of 16-bit UUIDs 2172 while (len > 1) { 2173 int uuid16 = adv_data[offset++]; 2174 uuid16 += (adv_data[offset++] << 8); 2175 len -= 2; 2176 uuids.add(UUID.fromString(String.format( 2177 "%08x-0000-1000-8000-00805f9b34fb", uuid16))); 2178 } 2179 break; 2180 2181 default: 2182 offset += (len - 1); 2183 break; 2184 } 2185 } 2186 2187 return uuids; 2188 } 2189 2190 @Override 2191 public void dump(StringBuilder sb) { 2192 super.dump(sb); 2193 println(sb, "mAdvertisingServiceUuids:"); 2194 for (UUID uuid : mAdvertisingServiceUuids) { 2195 println(sb, " " + uuid); 2196 } 2197 println(sb, "mOnFoundResults:"); 2198 for (ScanResult result : mOnFoundResults.values()) { 2199 println(sb, " " + result); 2200 } 2201 println(sb, "mOnFoundResults:"); 2202 for (ServiceDeclaration declaration : mServiceDeclarations) { 2203 println(sb, " " + declaration); 2204 } 2205 println(sb, "mMaxScanFilters: " + mMaxScanFilters); 2206 } 2207 2208 /************************************************************************** 2209 * GATT Test functions 2210 *************************************************************************/ 2211 2212 void gattTestCommand(int command, UUID uuid1, String bda1, 2213 int p1, int p2, int p3, int p4, int p5) { 2214 if (bda1 == null) bda1 = "00:00:00:00:00:00"; 2215 if (uuid1 != null) 2216 gattTestNative(command, uuid1.getLeastSignificantBits(), 2217 uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5); 2218 else 2219 gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5); 2220 } 2221 2222 private native void gattTestNative(int command, 2223 long uuid1_lsb, long uuid1_msb, String bda1, 2224 int p1, int p2, int p3, int p4, int p5); 2225 2226 /************************************************************************** 2227 * Native functions prototypes 2228 *************************************************************************/ 2229 2230 private native static void classInitNative(); 2231 private native void initializeNative(); 2232 private native void cleanupNative(); 2233 2234 private native int gattClientGetDeviceTypeNative(String address); 2235 2236 private native void gattClientRegisterAppNative(long app_uuid_lsb, 2237 long app_uuid_msb); 2238 2239 private native void gattClientUnregisterAppNative(int clientIf); 2240 2241 private native void gattClientConnectNative(int clientIf, String address, 2242 boolean isDirect, int transport); 2243 2244 private native void gattClientDisconnectNative(int clientIf, String address, 2245 int conn_id); 2246 2247 private native void gattClientRefreshNative(int clientIf, String address); 2248 2249 private native void gattClientSearchServiceNative(int conn_id, 2250 boolean search_all, long service_uuid_lsb, long service_uuid_msb); 2251 2252 private native void gattClientGetCharacteristicNative(int conn_id, 2253 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 2254 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 2255 long char_id_uuid_msb); 2256 2257 private native void gattClientGetDescriptorNative(int conn_id, int service_type, 2258 int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb, 2259 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 2260 int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb); 2261 2262 private native void gattClientGetIncludedServiceNative(int conn_id, 2263 int service_type, int service_id_inst_id, 2264 long service_id_uuid_lsb, long service_id_uuid_msb, 2265 int incl_service_id_inst_id, int incl_service_type, 2266 long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb); 2267 2268 private native void gattClientReadCharacteristicNative(int conn_id, 2269 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 2270 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 2271 long char_id_uuid_msb, int authReq); 2272 2273 private native void gattClientReadDescriptorNative(int conn_id, int service_type, 2274 int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb, 2275 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 2276 int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb, 2277 int authReq); 2278 2279 private native void gattClientWriteCharacteristicNative(int conn_id, 2280 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 2281 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 2282 long char_id_uuid_msb, int write_type, int auth_req, byte[] value); 2283 2284 private native void gattClientWriteDescriptorNative(int conn_id, int service_type, 2285 int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb, 2286 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 2287 int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb, 2288 int write_type, int auth_req, byte[] value); 2289 2290 private native void gattClientExecuteWriteNative(int conn_id, boolean execute); 2291 2292 private native void gattClientRegisterForNotificationsNative(int clientIf, 2293 String address, int service_type, int service_id_inst_id, 2294 long service_id_uuid_lsb, long service_id_uuid_msb, 2295 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 2296 boolean enable); 2297 2298 private native void gattClientReadRemoteRssiNative(int clientIf, 2299 String address); 2300 2301 private native void gattClientConfigureMTUNative(int conn_id, int mtu); 2302 2303 private native void gattConnectionParameterUpdateNative(int client_if, String address, 2304 int minInterval, int maxInterval, int latency, int timeout); 2305 2306 private native void gattServerRegisterAppNative(long app_uuid_lsb, 2307 long app_uuid_msb); 2308 2309 private native void gattServerUnregisterAppNative(int serverIf); 2310 2311 private native void gattServerConnectNative(int server_if, String address, 2312 boolean is_direct, int transport); 2313 2314 private native void gattServerDisconnectNative(int serverIf, String address, 2315 int conn_id); 2316 2317 private native void gattServerAddServiceNative (int server_if, 2318 int service_type, int service_id_inst_id, 2319 long service_id_uuid_lsb, long service_id_uuid_msb, 2320 int num_handles); 2321 2322 private native void gattServerAddIncludedServiceNative (int server_if, 2323 int svc_handle, int included_svc_handle); 2324 2325 private native void gattServerAddCharacteristicNative (int server_if, 2326 int svc_handle, long char_uuid_lsb, long char_uuid_msb, 2327 int properties, int permissions); 2328 2329 private native void gattServerAddDescriptorNative (int server_if, 2330 int svc_handle, long desc_uuid_lsb, long desc_uuid_msb, 2331 int permissions); 2332 2333 private native void gattServerStartServiceNative (int server_if, 2334 int svc_handle, int transport ); 2335 2336 private native void gattServerStopServiceNative (int server_if, 2337 int svc_handle); 2338 2339 private native void gattServerDeleteServiceNative (int server_if, 2340 int svc_handle); 2341 2342 private native void gattServerSendIndicationNative (int server_if, 2343 int attr_handle, int conn_id, byte[] val); 2344 2345 private native void gattServerSendNotificationNative (int server_if, 2346 int attr_handle, int conn_id, byte[] val); 2347 2348 private native void gattServerSendResponseNative (int server_if, 2349 int conn_id, int trans_id, int status, int handle, int offset, 2350 byte[] val, int auth_req); 2351} 2352