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