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