GattService.java revision cc633970b1fc16db030da1634a0c92fa3548a465
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 if (DBG) Log.d(TAG, "onAttributeRead() UUID=" + entry.uuid 1692 + ", serverIf=" + entry.serverIf + ", type=" + entry.type); 1693 1694 mHandleMap.addRequest(transId, attrHandle); 1695 1696 ServerMap.App app = mServerMap.getById(entry.serverIf); 1697 if (app == null) return; 1698 1699 switch(entry.type) { 1700 case HandleMap.TYPE_CHARACTERISTIC: 1701 { 1702 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1703 app.callback.onCharacteristicReadRequest(address, transId, offset, isLong, 1704 serviceEntry.serviceType, serviceEntry.instance, 1705 new ParcelUuid(serviceEntry.uuid), entry.instance, 1706 new ParcelUuid(entry.uuid)); 1707 break; 1708 } 1709 1710 case HandleMap.TYPE_DESCRIPTOR: 1711 { 1712 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1713 HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle); 1714 app.callback.onDescriptorReadRequest(address, transId, offset, isLong, 1715 serviceEntry.serviceType, serviceEntry.instance, 1716 new ParcelUuid(serviceEntry.uuid), charEntry.instance, 1717 new ParcelUuid(charEntry.uuid), 1718 new ParcelUuid(entry.uuid)); 1719 break; 1720 } 1721 1722 default: 1723 Log.e(TAG, "onAttributeRead() - Requested unknown attribute type."); 1724 break; 1725 } 1726 } 1727 1728 void onAttributeWrite(String address, int connId, int transId, 1729 int attrHandle, int offset, int length, 1730 boolean needRsp, boolean isPrep, 1731 byte[] data) 1732 throws RemoteException { 1733 if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId 1734 + ", address=" + address + ", handle=" + attrHandle 1735 + ", requestId=" + transId + ", isPrep=" + isPrep 1736 + ", offset=" + offset); 1737 1738 HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle); 1739 if (entry == null) return; 1740 1741 if (DBG) Log.d(TAG, "onAttributeWrite() UUID=" + entry.uuid 1742 + ", serverIf=" + entry.serverIf + ", type=" + entry.type); 1743 1744 mHandleMap.addRequest(transId, attrHandle); 1745 1746 ServerMap.App app = mServerMap.getById(entry.serverIf); 1747 if (app == null) return; 1748 1749 switch(entry.type) { 1750 case HandleMap.TYPE_CHARACTERISTIC: 1751 { 1752 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1753 app.callback.onCharacteristicWriteRequest(address, transId, 1754 offset, length, isPrep, needRsp, 1755 serviceEntry.serviceType, serviceEntry.instance, 1756 new ParcelUuid(serviceEntry.uuid), entry.instance, 1757 new ParcelUuid(entry.uuid), data); 1758 break; 1759 } 1760 1761 case HandleMap.TYPE_DESCRIPTOR: 1762 { 1763 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle); 1764 HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle); 1765 app.callback.onDescriptorWriteRequest(address, transId, 1766 offset, length, isPrep, needRsp, 1767 serviceEntry.serviceType, serviceEntry.instance, 1768 new ParcelUuid(serviceEntry.uuid), charEntry.instance, 1769 new ParcelUuid(charEntry.uuid), 1770 new ParcelUuid(entry.uuid), data); 1771 break; 1772 } 1773 1774 default: 1775 Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type."); 1776 break; 1777 } 1778 } 1779 1780 void onExecuteWrite(String address, int connId, int transId, int execWrite) 1781 throws RemoteException { 1782 if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId 1783 + ", address=" + address + ", transId=" + transId); 1784 1785 ServerMap.App app = mServerMap.getByConnId(connId); 1786 if (app == null) return; 1787 1788 app.callback.onExecuteWrite(address, transId, execWrite == 1); 1789 } 1790 1791 void onResponseSendCompleted(int status, int attrHandle) { 1792 if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle); 1793 } 1794 1795 void onNotificationSent(int connId, int status) throws RemoteException { 1796 if (DBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status); 1797 1798 String address = mServerMap.addressByConnId(connId); 1799 if (address == null) return; 1800 1801 ServerMap.App app = mServerMap.getByConnId(connId); 1802 if (app == null) return; 1803 1804 if (!app.isCongested) { 1805 app.callback.onNotificationSent(address, status); 1806 } else { 1807 if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) { 1808 status = BluetoothGatt.GATT_SUCCESS; 1809 } 1810 app.queueCallback(new CallbackInfo(address, status)); 1811 } 1812 } 1813 1814 void onServerCongestion(int connId, boolean congested) throws RemoteException { 1815 if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested); 1816 1817 ServerMap.App app = mServerMap.getByConnId(connId); 1818 if (app == null) return; 1819 1820 app.isCongested = congested; 1821 while(!app.isCongested) { 1822 CallbackInfo callbackInfo = app.popQueuedCallback(); 1823 if (callbackInfo == null) return; 1824 app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status); 1825 } 1826 } 1827 1828 /************************************************************************** 1829 * GATT Service functions - SERVER 1830 *************************************************************************/ 1831 1832 void registerServer(UUID uuid, IBluetoothGattServerCallback callback) { 1833 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1834 1835 if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid); 1836 mServerMap.add(uuid, callback); 1837 gattServerRegisterAppNative(uuid.getLeastSignificantBits(), 1838 uuid.getMostSignificantBits()); 1839 } 1840 1841 void unregisterServer(int serverIf) { 1842 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1843 1844 if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf); 1845 1846 deleteServices(serverIf); 1847 1848 mServerMap.remove(serverIf); 1849 gattServerUnregisterAppNative(serverIf); 1850 } 1851 1852 void serverConnect(int serverIf, String address, boolean isDirect, int transport) { 1853 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1854 1855 if (DBG) Log.d(TAG, "serverConnect() - address=" + address); 1856 gattServerConnectNative(serverIf, address, isDirect,transport); 1857 } 1858 1859 void serverDisconnect(int serverIf, String address) { 1860 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1861 1862 Integer connId = mServerMap.connIdByAddress(serverIf, address); 1863 if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId); 1864 1865 gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0); 1866 } 1867 1868 void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId, 1869 int minHandles, UUID srvcUuid, boolean advertisePreferred) { 1870 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1871 1872 if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid); 1873 ServiceDeclaration serviceDeclaration = addDeclaration(); 1874 serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles, 1875 advertisePreferred); 1876 } 1877 1878 void addIncludedService(int serverIf, int srvcType, int srvcInstanceId, 1879 UUID srvcUuid) { 1880 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1881 1882 if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid); 1883 getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId); 1884 } 1885 1886 void addCharacteristic(int serverIf, UUID charUuid, int properties, 1887 int permissions) { 1888 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1889 1890 if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid); 1891 getActiveDeclaration().addCharacteristic(charUuid, properties, permissions); 1892 } 1893 1894 void addDescriptor(int serverIf, UUID descUuid, int permissions) { 1895 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1896 1897 if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid); 1898 getActiveDeclaration().addDescriptor(descUuid, permissions); 1899 } 1900 1901 void endServiceDeclaration(int serverIf) { 1902 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1903 1904 if (DBG) Log.d(TAG, "endServiceDeclaration()"); 1905 1906 if (getActiveDeclaration() == getPendingDeclaration()) { 1907 try { 1908 continueServiceDeclaration(serverIf, (byte)0, 0); 1909 } catch (RemoteException e) { 1910 Log.e(TAG,""+e); 1911 } 1912 } 1913 } 1914 1915 void removeService(int serverIf, int srvcType, 1916 int srvcInstanceId, UUID srvcUuid) { 1917 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1918 1919 if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid); 1920 1921 int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId); 1922 if (srvcHandle == 0) return; 1923 gattServerDeleteServiceNative(serverIf, srvcHandle); 1924 } 1925 1926 void clearServices(int serverIf) { 1927 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1928 1929 if (DBG) Log.d(TAG, "clearServices()"); 1930 deleteServices(serverIf); 1931 } 1932 1933 void sendResponse(int serverIf, String address, int requestId, 1934 int status, int offset, byte[] value) { 1935 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1936 1937 if (VDBG) Log.d(TAG, "sendResponse() - address=" + address); 1938 1939 int handle = 0; 1940 HandleMap.Entry entry = mHandleMap.getByRequestId(requestId); 1941 if (entry != null) handle = entry.handle; 1942 1943 int connId = mServerMap.connIdByAddress(serverIf, address); 1944 gattServerSendResponseNative(serverIf, connId, requestId, (byte)status, 1945 handle, offset, value, (byte)0); 1946 mHandleMap.deleteRequest(requestId); 1947 } 1948 1949 void sendNotification(int serverIf, String address, int srvcType, 1950 int srvcInstanceId, UUID srvcUuid, 1951 int charInstanceId, UUID charUuid, 1952 boolean confirm, byte[] value) { 1953 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1954 1955 if (VDBG) Log.d(TAG, "sendNotification() - address=" + address); 1956 1957 int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId); 1958 if (srvcHandle == 0) return; 1959 1960 int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId); 1961 if (charHandle == 0) return; 1962 1963 int connId = mServerMap.connIdByAddress(serverIf, address); 1964 if (connId == 0) return; 1965 1966 if (confirm) { 1967 gattServerSendIndicationNative(serverIf, charHandle, connId, value); 1968 } else { 1969 gattServerSendNotificationNative(serverIf, charHandle, connId, value); 1970 } 1971 } 1972 1973 1974 /************************************************************************** 1975 * Private functions 1976 *************************************************************************/ 1977 1978 private int getDeviceType(BluetoothDevice device) { 1979 int type = gattClientGetDeviceTypeNative(device.getAddress()); 1980 if (DBG) Log.d(TAG, "getDeviceType() - device=" + device 1981 + ", type=" + type); 1982 return type; 1983 } 1984 1985 private void enforceAdminPermission() { 1986 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 1987 } 1988 1989 private boolean needsPrivilegedPermissionForScan(ScanSettings settings) { 1990 // Regular scan, no special permission. 1991 if (settings == null) { 1992 return false; 1993 } 1994 // Hidden API for onLost/onFound 1995 if (settings.getCallbackType() != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { 1996 return true; 1997 } 1998 // Regular scan, no special permission. 1999 if (settings.getReportDelayMillis() == 0) { 2000 return false; 2001 } 2002 // Batch scan, truncated mode needs permission. 2003 return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED; 2004 } 2005 2006 // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be 2007 // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission. 2008 private void enforcePrivilegedPermission() { 2009 enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, 2010 "Need BLUETOOTH_PRIVILEGED permission"); 2011 } 2012 2013 private void continueSearch(int connId, int status) throws RemoteException { 2014 if (status == 0 && !mSearchQueue.isEmpty()) { 2015 SearchQueue.Entry svc = mSearchQueue.pop(); 2016 2017 if (svc.charUuidLsb == 0) { 2018 // Characteristic is up next 2019 gattClientGetCharacteristicNative(svc.connId, svc.srvcType, 2020 svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 0, 0, 0); 2021 } else { 2022 // Descriptor is up next 2023 gattClientGetDescriptorNative(svc.connId, svc.srvcType, 2024 svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb, 2025 svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0); 2026 } 2027 } else { 2028 ClientMap.App app = mClientMap.getByConnId(connId); 2029 if (app != null) { 2030 app.callback.onSearchComplete(mClientMap.addressByConnId(connId), status); 2031 } 2032 } 2033 } 2034 2035 private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException { 2036 if (mServiceDeclarations.size() == 0) return; 2037 if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle); 2038 2039 boolean finished = false; 2040 2041 ServiceDeclaration.Entry entry = null; 2042 if (status == 0) 2043 entry = getPendingDeclaration().getNext(); 2044 2045 if (entry != null) { 2046 if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type=" 2047 + entry.type); 2048 switch(entry.type) { 2049 case ServiceDeclaration.TYPE_SERVICE: 2050 if (entry.advertisePreferred) { 2051 mAdvertisingServiceUuids.add(entry.uuid); 2052 } 2053 gattServerAddServiceNative(serverIf, entry.serviceType, 2054 entry.instance, 2055 entry.uuid.getLeastSignificantBits(), 2056 entry.uuid.getMostSignificantBits(), 2057 getPendingDeclaration().getNumHandles()); 2058 break; 2059 2060 case ServiceDeclaration.TYPE_CHARACTERISTIC: 2061 gattServerAddCharacteristicNative(serverIf, srvcHandle, 2062 entry.uuid.getLeastSignificantBits(), 2063 entry.uuid.getMostSignificantBits(), 2064 entry.properties, entry.permissions); 2065 break; 2066 2067 case ServiceDeclaration.TYPE_DESCRIPTOR: 2068 gattServerAddDescriptorNative(serverIf, srvcHandle, 2069 entry.uuid.getLeastSignificantBits(), 2070 entry.uuid.getMostSignificantBits(), 2071 entry.permissions); 2072 break; 2073 2074 case ServiceDeclaration.TYPE_INCLUDED_SERVICE: 2075 { 2076 int inclSrvc = mHandleMap.getServiceHandle(entry.uuid, 2077 entry.serviceType, entry.instance); 2078 if (inclSrvc != 0) { 2079 gattServerAddIncludedServiceNative(serverIf, srvcHandle, 2080 inclSrvc); 2081 } else { 2082 finished = true; 2083 } 2084 break; 2085 } 2086 } 2087 } else { 2088 gattServerStartServiceNative(serverIf, srvcHandle, 2089 (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE); 2090 finished = true; 2091 } 2092 2093 if (finished) { 2094 if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed."); 2095 ServerMap.App app = mServerMap.getById(serverIf); 2096 if (app != null) { 2097 HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle); 2098 2099 if (serviceEntry != null) { 2100 app.callback.onServiceAdded(status, serviceEntry.serviceType, 2101 serviceEntry.instance, new ParcelUuid(serviceEntry.uuid)); 2102 } else { 2103 app.callback.onServiceAdded(status, 0, 0, null); 2104 } 2105 } 2106 removePendingDeclaration(); 2107 2108 if (getPendingDeclaration() != null) { 2109 continueServiceDeclaration(serverIf, (byte)0, 0); 2110 } 2111 } 2112 } 2113 2114 private void stopNextService(int serverIf, int status) throws RemoteException { 2115 if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf 2116 + ", status=" + status); 2117 2118 if (status == 0) { 2119 List<HandleMap.Entry> entries = mHandleMap.getEntries(); 2120 for(HandleMap.Entry entry : entries) { 2121 if (entry.type != HandleMap.TYPE_SERVICE || 2122 entry.serverIf != serverIf || 2123 entry.started == false) 2124 continue; 2125 2126 gattServerStopServiceNative(serverIf, entry.handle); 2127 return; 2128 } 2129 } 2130 } 2131 2132 private void deleteServices(int serverIf) { 2133 if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf); 2134 2135 /* 2136 * Figure out which handles to delete. 2137 * The handles are copied into a new list to avoid race conditions. 2138 */ 2139 List<Integer> handleList = new ArrayList<Integer>(); 2140 List<HandleMap.Entry> entries = mHandleMap.getEntries(); 2141 for(HandleMap.Entry entry : entries) { 2142 if (entry.type != HandleMap.TYPE_SERVICE || 2143 entry.serverIf != serverIf) 2144 continue; 2145 handleList.add(entry.handle); 2146 } 2147 2148 /* Now actually delete the services.... */ 2149 for(Integer handle : handleList) { 2150 gattServerDeleteServiceNative(serverIf, handle); 2151 } 2152 } 2153 2154 private List<UUID> parseUuids(byte[] adv_data) { 2155 List<UUID> uuids = new ArrayList<UUID>(); 2156 2157 int offset = 0; 2158 while(offset < (adv_data.length-2)) { 2159 int len = adv_data[offset++]; 2160 if (len == 0) break; 2161 2162 int type = adv_data[offset++]; 2163 switch (type) { 2164 case 0x02: // Partial list of 16-bit UUIDs 2165 case 0x03: // Complete list of 16-bit UUIDs 2166 while (len > 1) { 2167 int uuid16 = adv_data[offset++]; 2168 uuid16 += (adv_data[offset++] << 8); 2169 len -= 2; 2170 uuids.add(UUID.fromString(String.format( 2171 "%08x-0000-1000-8000-00805f9b34fb", uuid16))); 2172 } 2173 break; 2174 2175 default: 2176 offset += (len - 1); 2177 break; 2178 } 2179 } 2180 2181 return uuids; 2182 } 2183 2184 @Override 2185 public void dump(StringBuilder sb) { 2186 super.dump(sb); 2187 println(sb, "mAdvertisingServiceUuids:"); 2188 for (UUID uuid : mAdvertisingServiceUuids) { 2189 println(sb, " " + uuid); 2190 } 2191 println(sb, "mOnFoundResults:"); 2192 for (ScanResult result : mOnFoundResults.values()) { 2193 println(sb, " " + result); 2194 } 2195 println(sb, "mOnFoundResults:"); 2196 for (ServiceDeclaration declaration : mServiceDeclarations) { 2197 println(sb, " " + declaration); 2198 } 2199 println(sb, "mMaxScanFilters: " + mMaxScanFilters); 2200 } 2201 2202 /************************************************************************** 2203 * GATT Test functions 2204 *************************************************************************/ 2205 2206 void gattTestCommand(int command, UUID uuid1, String bda1, 2207 int p1, int p2, int p3, int p4, int p5) { 2208 if (bda1 == null) bda1 = "00:00:00:00:00:00"; 2209 if (uuid1 != null) 2210 gattTestNative(command, uuid1.getLeastSignificantBits(), 2211 uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5); 2212 else 2213 gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5); 2214 } 2215 2216 private native void gattTestNative(int command, 2217 long uuid1_lsb, long uuid1_msb, String bda1, 2218 int p1, int p2, int p3, int p4, int p5); 2219 2220 /************************************************************************** 2221 * Native functions prototypes 2222 *************************************************************************/ 2223 2224 private native static void classInitNative(); 2225 private native void initializeNative(); 2226 private native void cleanupNative(); 2227 2228 private native int gattClientGetDeviceTypeNative(String address); 2229 2230 private native void gattClientRegisterAppNative(long app_uuid_lsb, 2231 long app_uuid_msb); 2232 2233 private native void gattClientUnregisterAppNative(int clientIf); 2234 2235 private native void gattClientConnectNative(int clientIf, String address, 2236 boolean isDirect, int transport); 2237 2238 private native void gattClientDisconnectNative(int clientIf, String address, 2239 int conn_id); 2240 2241 private native void gattClientRefreshNative(int clientIf, String address); 2242 2243 private native void gattClientSearchServiceNative(int conn_id, 2244 boolean search_all, long service_uuid_lsb, long service_uuid_msb); 2245 2246 private native void gattClientGetCharacteristicNative(int conn_id, 2247 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 2248 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 2249 long char_id_uuid_msb); 2250 2251 private native void gattClientGetDescriptorNative(int conn_id, int service_type, 2252 int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb, 2253 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 2254 int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb); 2255 2256 private native void gattClientGetIncludedServiceNative(int conn_id, 2257 int service_type, int service_id_inst_id, 2258 long service_id_uuid_lsb, long service_id_uuid_msb, 2259 int incl_service_id_inst_id, int incl_service_type, 2260 long incl_service_id_uuid_lsb, long incl_service_id_uuid_msb); 2261 2262 private native void gattClientReadCharacteristicNative(int conn_id, 2263 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 2264 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 2265 long char_id_uuid_msb, int authReq); 2266 2267 private native void gattClientReadDescriptorNative(int conn_id, int service_type, 2268 int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb, 2269 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 2270 int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb, 2271 int authReq); 2272 2273 private native void gattClientWriteCharacteristicNative(int conn_id, 2274 int service_type, int service_id_inst_id, long service_id_uuid_lsb, 2275 long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb, 2276 long char_id_uuid_msb, int write_type, int auth_req, byte[] value); 2277 2278 private native void gattClientWriteDescriptorNative(int conn_id, int service_type, 2279 int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb, 2280 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 2281 int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb, 2282 int write_type, int auth_req, byte[] value); 2283 2284 private native void gattClientExecuteWriteNative(int conn_id, boolean execute); 2285 2286 private native void gattClientRegisterForNotificationsNative(int clientIf, 2287 String address, int service_type, int service_id_inst_id, 2288 long service_id_uuid_lsb, long service_id_uuid_msb, 2289 int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb, 2290 boolean enable); 2291 2292 private native void gattClientReadRemoteRssiNative(int clientIf, 2293 String address); 2294 2295 private native void gattClientConfigureMTUNative(int conn_id, int mtu); 2296 2297 private native void gattConnectionParameterUpdateNative(int client_if, String address, 2298 int minInterval, int maxInterval, int latency, int timeout); 2299 2300 private native void gattServerRegisterAppNative(long app_uuid_lsb, 2301 long app_uuid_msb); 2302 2303 private native void gattServerUnregisterAppNative(int serverIf); 2304 2305 private native void gattServerConnectNative(int server_if, String address, 2306 boolean is_direct, int transport); 2307 2308 private native void gattServerDisconnectNative(int serverIf, String address, 2309 int conn_id); 2310 2311 private native void gattServerAddServiceNative (int server_if, 2312 int service_type, int service_id_inst_id, 2313 long service_id_uuid_lsb, long service_id_uuid_msb, 2314 int num_handles); 2315 2316 private native void gattServerAddIncludedServiceNative (int server_if, 2317 int svc_handle, int included_svc_handle); 2318 2319 private native void gattServerAddCharacteristicNative (int server_if, 2320 int svc_handle, long char_uuid_lsb, long char_uuid_msb, 2321 int properties, int permissions); 2322 2323 private native void gattServerAddDescriptorNative (int server_if, 2324 int svc_handle, long desc_uuid_lsb, long desc_uuid_msb, 2325 int permissions); 2326 2327 private native void gattServerStartServiceNative (int server_if, 2328 int svc_handle, int transport ); 2329 2330 private native void gattServerStopServiceNative (int server_if, 2331 int svc_handle); 2332 2333 private native void gattServerDeleteServiceNative (int server_if, 2334 int svc_handle); 2335 2336 private native void gattServerSendIndicationNative (int server_if, 2337 int attr_handle, int conn_id, byte[] val); 2338 2339 private native void gattServerSendNotificationNative (int server_if, 2340 int attr_handle, int conn_id, byte[] val); 2341 2342 private native void gattServerSendResponseNative (int server_if, 2343 int conn_id, int trans_id, int status, int handle, int offset, 2344 byte[] val, int auth_req); 2345} 2346