1 /* 2 * Copyright (C) 2016 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.googlecode.android_scripting.facade.bluetooth; 18 19 import java.util.ArrayList; 20 import java.util.HashMap; 21 import java.util.List; 22 import java.util.UUID; 23 import java.util.concurrent.Callable; 24 25 import android.app.Service; 26 import android.bluetooth.BluetoothAdapter; 27 import android.bluetooth.BluetoothDevice; 28 import android.bluetooth.BluetoothGatt; 29 import android.bluetooth.BluetoothGattCallback; 30 import android.bluetooth.BluetoothManager; 31 import android.bluetooth.BluetoothGattCharacteristic; 32 import android.bluetooth.BluetoothGattDescriptor; 33 import android.bluetooth.BluetoothGattService; 34 import android.bluetooth.BluetoothProfile; 35 import android.content.Context; 36 import android.os.Bundle; 37 38 import com.googlecode.android_scripting.ConvertUtils; 39 import com.googlecode.android_scripting.Log; 40 import com.googlecode.android_scripting.MainThread; 41 import com.googlecode.android_scripting.facade.EventFacade; 42 import com.googlecode.android_scripting.facade.FacadeManager; 43 import com.googlecode.android_scripting.jsonrpc.RpcReceiver; 44 import com.googlecode.android_scripting.rpc.Rpc; 45 import com.googlecode.android_scripting.rpc.RpcParameter; 46 import com.googlecode.android_scripting.rpc.RpcStopEvent; 47 48 public class GattClientFacade extends RpcReceiver { 49 private final EventFacade mEventFacade; 50 private BluetoothAdapter mBluetoothAdapter; 51 private BluetoothManager mBluetoothManager; 52 private final Service mService; 53 private final Context mContext; 54 private final HashMap<Integer, myBluetoothGattCallback> mGattCallbackList; 55 private final HashMap<Integer, BluetoothGatt> mBluetoothGattList; 56 private final HashMap<Integer, BluetoothGattCharacteristic> mCharacteristicList; 57 private final HashMap<Integer, BluetoothGattDescriptor> mDescriptorList; 58 private final HashMap<Integer, BluetoothGattService> mGattServiceList; 59 private final HashMap<Integer, List<BluetoothGattService>> mBluetoothGattDiscoveredServicesList; 60 private final HashMap<Integer, List<BluetoothDevice>> mGattServerDiscoveredDevicesList; 61 private static int GattCallbackCount; 62 private static int BluetoothGattDiscoveredServicesCount; 63 private static int BluetoothGattCount; 64 private static int CharacteristicCount; 65 private static int DescriptorCount; 66 private static int GattServerCallbackCount; 67 private static int GattServerCount; 68 private static int GattServiceCount; 69 GattClientFacade(FacadeManager manager)70 public GattClientFacade(FacadeManager manager) { 71 super(manager); 72 mService = manager.getService(); 73 mContext = mService.getApplicationContext(); 74 mBluetoothAdapter = MainThread.run(mService, 75 new Callable<BluetoothAdapter>() { 76 @Override 77 public BluetoothAdapter call() throws Exception { 78 return BluetoothAdapter.getDefaultAdapter(); 79 } 80 }); 81 mBluetoothManager = (BluetoothManager) mContext.getSystemService(Service.BLUETOOTH_SERVICE); 82 mEventFacade = manager.getReceiver(EventFacade.class); 83 mGattCallbackList = new HashMap<Integer, myBluetoothGattCallback>(); 84 mCharacteristicList = new HashMap<Integer, BluetoothGattCharacteristic>(); 85 mBluetoothGattList = new HashMap<Integer, BluetoothGatt>(); 86 mDescriptorList = new HashMap<Integer, BluetoothGattDescriptor>(); 87 mGattServiceList = new HashMap<Integer, BluetoothGattService>(); 88 mBluetoothGattDiscoveredServicesList = new HashMap<Integer, List<BluetoothGattService>>(); 89 mGattServerDiscoveredDevicesList = new HashMap<Integer, List<BluetoothDevice>>(); 90 } 91 92 /** 93 * Create a BluetoothGatt connection 94 * 95 * @param index of the callback to start a connection on 96 * @param macAddress the mac address of the ble device 97 * @param autoConnect Whether to directly connect to the remote device (false) or to 98 * automatically connect as soon as the remote device becomes available (true) 99 * @return the index of the BluetoothGatt object 100 * @throws Exception 101 */ 102 @Rpc(description = "Create a gatt connection") gattClientConnectGatt( @pcParametername = "index") Integer index, @RpcParameter(name = "macAddress") String macAddress, @RpcParameter(name = "autoConnect") Boolean autoConnect )103 public int gattClientConnectGatt( 104 @RpcParameter(name = "index") 105 Integer index, 106 @RpcParameter(name = "macAddress") 107 String macAddress, 108 @RpcParameter(name = "autoConnect") 109 Boolean autoConnect 110 ) throws Exception { 111 if (mGattCallbackList.get(index) != null) { 112 BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(macAddress); 113 BluetoothGatt mBluetoothGatt = device.connectGatt(mService.getApplicationContext(), 114 autoConnect, 115 mGattCallbackList.get(index)); 116 BluetoothGattCount += 1; 117 mBluetoothGattList.put(BluetoothGattCount, mBluetoothGatt); 118 return BluetoothGattCount; 119 } else { 120 throw new Exception("Invalid index input:" + Integer.toString(index)); 121 } 122 } 123 124 /** 125 * Trigger discovering of services on the BluetoothGatt object 126 * 127 * @param index The BluetoothGatt object index 128 * @return true, if the remote service discovery has been started 129 * @throws Exception 130 */ 131 @Rpc(description = "Trigger discovering of services on the BluetoothGatt object") gattClientDiscoverServices( @pcParametername = "index") Integer index )132 public boolean gattClientDiscoverServices( 133 @RpcParameter(name = "index") 134 Integer index 135 ) throws Exception { 136 if (mBluetoothGattList.get(index) != null) { 137 return mBluetoothGattList.get(index).discoverServices(); 138 } else { 139 throw new Exception("Invalid index input:" + Integer.toString(index)); 140 } 141 } 142 143 /** 144 * Get the services from the BluetoothGatt object 145 * 146 * @param index The BluetoothGatt object index 147 * @return a list of BluetoothGattServices 148 * @throws Exception 149 */ 150 @Rpc(description = "Get the services from the BluetoothGatt object") gattClientGetServices( @pcParametername = "index") Integer index )151 public List<BluetoothGattService> gattClientGetServices( 152 @RpcParameter(name = "index") 153 Integer index 154 ) throws Exception { 155 if (mBluetoothGattList.get(index) != null) { 156 return mBluetoothGattList.get(index).getServices(); 157 } else { 158 throw new Exception("Invalid index input:" + Integer.toString(index)); 159 } 160 } 161 162 /** 163 * Abort reliable write of a bluetooth gatt 164 * 165 * @param index the bluetooth gatt index 166 * @throws Exception 167 */ 168 @Rpc(description = "Abort reliable write of a bluetooth gatt") gattClientAbortReliableWrite( @pcParametername = "index") Integer index )169 public void gattClientAbortReliableWrite( 170 @RpcParameter(name = "index") 171 Integer index 172 ) throws Exception { 173 if (mBluetoothGattList.get(index) != null) { 174 mBluetoothGattList.get(index).abortReliableWrite(); 175 } else { 176 throw new Exception("Invalid index input:" + index); 177 } 178 } 179 180 /** 181 * Begin reliable write of a bluetooth gatt 182 * 183 * @param index the bluetooth gatt index 184 * @return 185 * @throws Exception 186 */ 187 @Rpc(description = "Begin reliable write of a bluetooth gatt") gattClientBeginReliableWrite( @pcParametername = "index") Integer index )188 public boolean gattClientBeginReliableWrite( 189 @RpcParameter(name = "index") 190 Integer index 191 ) throws Exception { 192 if (mBluetoothGattList.get(index) != null) { 193 return mBluetoothGattList.get(index).beginReliableWrite(); 194 } else { 195 throw new Exception("Invalid index input:" + index); 196 } 197 } 198 199 /** 200 * Configure a bluetooth gatt's MTU 201 * 202 * @param index the bluetooth gatt index 203 * @param mtu the MTU to set 204 * @return 205 * @throws Exception 206 */ 207 @Rpc(description = "true, if the new MTU value has been requested successfully") gattClientRequestMtu( @pcParametername = "index") Integer index, @RpcParameter(name = "mtu") Integer mtu )208 public boolean gattClientRequestMtu( 209 @RpcParameter(name = "index") 210 Integer index, 211 @RpcParameter(name = "mtu") 212 Integer mtu 213 ) throws Exception { 214 if (mBluetoothGattList.get(index) != null) { 215 return mBluetoothGattList.get(index).requestMtu(mtu); 216 } else { 217 throw new Exception("Invalid index input:" + index); 218 } 219 } 220 221 /** 222 * Disconnect a bluetooth gatt 223 * 224 * @param index the bluetooth gatt index 225 * @throws Exception 226 */ 227 @Rpc(description = "Disconnect a bluetooth gatt") 228 @RpcStopEvent("GattConnect") gattClientDisconnect( @pcParametername = "index") Integer index )229 public void gattClientDisconnect( 230 @RpcParameter(name = "index") 231 Integer index 232 ) throws Exception { 233 if (mBluetoothGattList.get(index) != null) { 234 mBluetoothGattList.get(index).disconnect(); 235 } else { 236 throw new Exception("Invalid index input: " + index); 237 } 238 } 239 240 /** 241 * Close a bluetooth gatt object 242 * 243 * @param index the bluetooth gatt index 244 * @throws Exception 245 */ 246 @Rpc(description = "Close a Bluetooth GATT object") gattClientClose( @pcParametername = "index") Integer index )247 public void gattClientClose( 248 @RpcParameter(name = "index") 249 Integer index 250 ) throws Exception { 251 if (mBluetoothGattList.get(index) != null) { 252 mBluetoothGattList.get(index).close(); 253 } else { 254 throw new Exception("Invalid index input: " + index); 255 } 256 } 257 258 /** 259 * Execute reliable write on a bluetooth gatt 260 * 261 * @param index the bluetooth gatt index 262 * @return true, if the request to execute the transaction has been sent 263 * @throws Exception 264 */ 265 @Rpc(description = "Execute reliable write on a bluetooth gatt") gattExecuteReliableWrite( @pcParametername = "index") Integer index )266 public boolean gattExecuteReliableWrite( 267 @RpcParameter(name = "index") 268 Integer index 269 ) throws Exception { 270 if (mBluetoothGattList.get(index) != null) { 271 return mBluetoothGattList.get(index).executeReliableWrite(); 272 } else { 273 throw new Exception("Invalid index input:" + index); 274 } 275 } 276 277 /** 278 * Get a list of Bluetooth Devices connnected to the bluetooth gatt 279 * 280 * @param index the bluetooth gatt index 281 * @return List of BluetoothDevice Objects 282 * @throws Exception 283 */ 284 @Rpc(description = "Get a list of Bluetooth Devices connnected to the bluetooth gatt") gattClientGetConnectedDevices( @pcParametername = "index") Integer index )285 public List<BluetoothDevice> gattClientGetConnectedDevices( 286 @RpcParameter(name = "index") 287 Integer index 288 ) throws Exception { 289 if (mBluetoothGattList.get(index) != null) { 290 return mBluetoothGattList.get(index).getConnectedDevices(); 291 } else { 292 throw new Exception("Invalid index input:" + index); 293 } 294 } 295 296 /** 297 * Get the remote bluetooth device this GATT client targets to 298 * 299 * @param index the bluetooth gatt index 300 * @return the remote bluetooth device this gatt client targets to 301 * @throws Exception 302 */ 303 @Rpc(description = "Get the remote bluetooth device this GATT client targets to") gattGetDevice( @pcParametername = "index") Integer index )304 public BluetoothDevice gattGetDevice( 305 @RpcParameter(name = "index") 306 Integer index 307 ) throws Exception { 308 if (mBluetoothGattList.get(index) != null) { 309 return mBluetoothGattList.get(index).getDevice(); 310 } else { 311 throw new Exception("Invalid index input:" + index); 312 } 313 } 314 315 /** 316 * Get the bluetooth devices matching input connection states 317 * 318 * @param index the bluetooth gatt index 319 * @param states the list of states to match 320 * @return The list of BluetoothDevice objects that match the states 321 * @throws Exception 322 */ 323 @Rpc(description = "Get the bluetooth devices matching input connection states") gattClientGetDevicesMatchingConnectionStates( @pcParametername = "index") Integer index, @RpcParameter(name = "states") int[] states )324 public List<BluetoothDevice> gattClientGetDevicesMatchingConnectionStates( 325 @RpcParameter(name = "index") 326 Integer index, 327 @RpcParameter(name = "states") 328 int[] states 329 ) throws Exception { 330 if (mBluetoothGattList.get(index) != null) { 331 return mBluetoothGattList.get(index).getDevicesMatchingConnectionStates(states); 332 } else { 333 throw new Exception("Invalid index input:" + index); 334 } 335 } 336 337 /** 338 * Get the service from an input UUID 339 * 340 * @param index the bluetooth gatt index 341 * @return BluetoothGattService related to the bluetooth gatt 342 * @throws Exception 343 */ 344 @Rpc(description = "Get the service from an input UUID") gattClientGetServiceUuidList( @pcParametername = "index") Integer index )345 public ArrayList<String> gattClientGetServiceUuidList( 346 @RpcParameter(name = "index") 347 Integer index 348 ) throws Exception { 349 if (mBluetoothGattList.get(index) != null) { 350 ArrayList<String> serviceUuidList = new ArrayList<String>(); 351 for (BluetoothGattService service : mBluetoothGattList.get(index).getServices()) { 352 serviceUuidList.add(service.getUuid().toString()); 353 } 354 return serviceUuidList; 355 } else { 356 throw new Exception("Invalid index input:" + index); 357 } 358 } 359 360 /** 361 * Reads the requested characteristic from the associated remote device. 362 * @param gattIndex the BluetoothGatt server accociated with the device 363 * @param discoveredServiceListIndex the index returned from the discovered 364 * services callback 365 * @param serviceIndex the service index of the discovered services 366 * @param characteristicUuid the characteristic uuid to read 367 * @return true, if the read operation was initiated successfully 368 * @throws Exception 369 */ 370 @Rpc(description = "Reads the requested characteristic from the associated remote device.") gattClientReadCharacteristic( @pcParametername = "gattIndex") Integer gattIndex, @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid)371 public boolean gattClientReadCharacteristic( 372 @RpcParameter(name = "gattIndex") Integer gattIndex, 373 @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, 374 @RpcParameter(name = "serviceIndex") Integer serviceIndex, 375 @RpcParameter(name = "characteristicUuid") String characteristicUuid) throws Exception { 376 BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex); 377 if (bluetoothGatt == null) { 378 throw new Exception("Invalid gattIndex " + gattIndex); 379 } 380 List<BluetoothGattService> discoveredServiceList = 381 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex); 382 if (discoveredServiceList == null) { 383 throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex); 384 } 385 BluetoothGattService gattService = discoveredServiceList.get(serviceIndex); 386 if (gattService == null) { 387 throw new Exception("Invalid serviceIndex " + serviceIndex); 388 } 389 UUID cUuid = UUID.fromString(characteristicUuid); 390 BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid); 391 if (gattCharacteristic == null) { 392 throw new Exception("Invalid characteristic uuid: " + characteristicUuid); 393 } 394 return bluetoothGatt.readCharacteristic(gattCharacteristic); 395 } 396 397 /** 398 * Reads the value for a given descriptor from the associated remote device 399 * @param gattIndex - the gatt index to use 400 * @param discoveredServiceListIndex - the discvered serivice list index 401 * @param serviceIndex - the servce index of the discoveredServiceListIndex 402 * @param characteristicUuid - the characteristic uuid in which the descriptor is 403 * @param descriptorUuid - the descriptor uuid to read 404 * @return 405 * @throws Exception 406 */ 407 @Rpc(description = "Reads the value for a given descriptor from the associated remote device") gattClientReadDescriptor(@pcParametername = "gattIndex") Integer gattIndex, @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid, @RpcParameter(name = "descriptorUuid") String descriptorUuid)408 public boolean gattClientReadDescriptor(@RpcParameter(name = "gattIndex") Integer gattIndex, 409 @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, 410 @RpcParameter(name = "serviceIndex") Integer serviceIndex, 411 @RpcParameter(name = "characteristicUuid") String characteristicUuid, 412 @RpcParameter(name = "descriptorUuid") String descriptorUuid) throws Exception { 413 BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex); 414 if (bluetoothGatt == null) { 415 throw new Exception("Invalid gattIndex " + gattIndex); 416 } 417 List<BluetoothGattService> gattServiceList = mBluetoothGattDiscoveredServicesList.get( 418 discoveredServiceListIndex); 419 if (gattServiceList == null) { 420 throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex); 421 } 422 BluetoothGattService gattService = gattServiceList.get(serviceIndex); 423 if (gattService == null) { 424 throw new Exception("Invalid serviceIndex " + serviceIndex); 425 } 426 UUID cUuid = UUID.fromString(characteristicUuid); 427 BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid); 428 if (gattCharacteristic == null) { 429 throw new Exception("Invalid characteristic uuid: " + characteristicUuid); 430 } 431 UUID dUuid = UUID.fromString(descriptorUuid); 432 BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(dUuid); 433 if (gattDescriptor == null) { 434 throw new Exception("Invalid descriptor uuid: " + descriptorUuid); 435 } 436 return bluetoothGatt.readDescriptor(gattDescriptor); 437 } 438 439 /** 440 * Write the value of a given descriptor to the associated remote device 441 * 442 * @param index the bluetooth gatt index 443 * @param serviceIndex the service index to write to 444 * @param characteristicUuid the uuid where the descriptor lives 445 * @param descriptorIndex the descriptor index 446 * @return true, if the write operation was initiated successfully 447 * @throws Exception 448 */ 449 @Rpc(description = "Write the value of a given descriptor to the associated remote device") gattClientWriteDescriptor(@pcParametername = "gattIndex") Integer gattIndex, @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid, @RpcParameter(name = "descriptorUuid") String descriptorUuid)450 public boolean gattClientWriteDescriptor(@RpcParameter(name = "gattIndex") Integer gattIndex, 451 @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, 452 @RpcParameter(name = "serviceIndex") Integer serviceIndex, 453 @RpcParameter(name = "characteristicUuid") String characteristicUuid, 454 @RpcParameter(name = "descriptorUuid") String descriptorUuid) throws Exception { 455 BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex); 456 if (bluetoothGatt == null) { 457 throw new Exception("Invalid gattIndex " + gattIndex); 458 } 459 List<BluetoothGattService> discoveredServiceList = 460 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex); 461 if (discoveredServiceList == null) { 462 throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex); 463 } 464 BluetoothGattService gattService = discoveredServiceList.get(serviceIndex); 465 if (gattService == null) { 466 throw new Exception("Invalid serviceIndex " + serviceIndex); 467 } 468 UUID cUuid = UUID.fromString(characteristicUuid); 469 BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid); 470 if (gattCharacteristic == null) { 471 throw new Exception("Invalid characteristic uuid: " + characteristicUuid); 472 } 473 UUID dUuid = UUID.fromString(descriptorUuid); 474 BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(dUuid); 475 if (gattDescriptor == null) { 476 throw new Exception("Invalid descriptor uuid: " + descriptorUuid); 477 } 478 return bluetoothGatt.writeDescriptor(gattDescriptor); 479 } 480 481 /** 482 * Write the value to a discovered descriptor. 483 * @param gattIndex - the gatt index to use 484 * @param discoveredServiceListIndex - the discovered service list index 485 * @param serviceIndex - the service index of the discoveredServiceListIndex 486 * @param characteristicUuid - the characteristic uuid in which the descriptor is 487 * @param descriptorUuid - the descriptor uuid to read 488 * @param value - the value to set the descriptor to 489 * @return true is the value was set to the descriptor 490 * @throws Exception 491 */ 492 @Rpc(description = "Write the value of a given descriptor to the associated remote device") gattClientDescriptorSetValue(@pcParametername = "gattIndex") Integer gattIndex, @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid, @RpcParameter(name = "descriptorUuid") String descriptorUuid, @RpcParameter(name = "value") byte[] value)493 public boolean gattClientDescriptorSetValue(@RpcParameter(name = "gattIndex") Integer gattIndex, 494 @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, 495 @RpcParameter(name = "serviceIndex") Integer serviceIndex, 496 @RpcParameter(name = "characteristicUuid") String characteristicUuid, 497 @RpcParameter(name = "descriptorUuid") String descriptorUuid, 498 @RpcParameter(name = "value") byte[] value) throws Exception { 499 if (mBluetoothGattList.get(gattIndex) == null) { 500 throw new Exception("Invalid gattIndex " + gattIndex); 501 } 502 List<BluetoothGattService> discoveredServiceList = 503 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex); 504 if (discoveredServiceList == null) { 505 throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex); 506 } 507 BluetoothGattService gattService = discoveredServiceList.get(serviceIndex); 508 if (gattService == null) { 509 throw new Exception("Invalid serviceIndex " + serviceIndex); 510 } 511 UUID cUuid = UUID.fromString(characteristicUuid); 512 BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid); 513 if (gattCharacteristic == null) { 514 throw new Exception("Invalid characteristic uuid: " + characteristicUuid); 515 } 516 UUID dUuid = UUID.fromString(descriptorUuid); 517 BluetoothGattDescriptor gattDescriptor = gattCharacteristic.getDescriptor(dUuid); 518 if (gattDescriptor == null) { 519 throw new Exception("Invalid descriptor uuid: " + descriptorUuid); 520 } 521 return gattDescriptor.setValue(value); 522 } 523 524 /** 525 * Write the value of a given characteristic to the associated remote device 526 * 527 * @param index the bluetooth gatt index 528 * @param serviceIndex the service where the characteristic lives 529 * @param characteristicUuid the characteristic uuid to write to 530 * @return true, if the write operation was successful 531 * @throws Exception 532 */ 533 @Rpc(description = "Write the value of a given characteristic to the associated remote device") gattClientWriteCharacteristic(@pcParametername = "gattIndex") Integer gattIndex, @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid)534 public boolean gattClientWriteCharacteristic(@RpcParameter(name = "gattIndex") Integer gattIndex, 535 @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, 536 @RpcParameter(name = "serviceIndex") Integer serviceIndex, 537 @RpcParameter(name = "characteristicUuid") String characteristicUuid) throws Exception { 538 BluetoothGatt bluetoothGatt = mBluetoothGattList.get(gattIndex); 539 if (bluetoothGatt == null) { 540 throw new Exception("Invalid gattIndex " + gattIndex); 541 } 542 List<BluetoothGattService> discoveredServiceList = 543 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex); 544 if (discoveredServiceList == null) { 545 throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex); 546 } 547 BluetoothGattService gattService = discoveredServiceList.get(serviceIndex); 548 if (gattService == null) { 549 throw new Exception("Invalid serviceIndex " + serviceIndex); 550 } 551 UUID cUuid = UUID.fromString(characteristicUuid); 552 BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid); 553 if (gattCharacteristic == null) { 554 throw new Exception("Invalid characteristic uuid: " + characteristicUuid); 555 } 556 return bluetoothGatt.writeCharacteristic(gattCharacteristic); 557 } 558 559 /** 560 * Write the value to a discovered characteristic. 561 * @param gattIndex - the gatt index to use 562 * @param discoveredServiceListIndex - the discovered service list index 563 * @param serviceIndex - the service index of the discoveredServiceListIndex 564 * @param characteristicUuid - the characteristic uuid in which the descriptor is 565 * @param value - the value to set the characteristic to 566 * @return true, if the value was set to the characteristic 567 * @throws Exception 568 */ 569 @Rpc(description = "Write the value of a given characteristic to the associated remote device") gattClientCharacteristicSetValue(@pcParametername = "gattIndex") Integer gattIndex, @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid, @RpcParameter(name = "value") byte[] value)570 public boolean gattClientCharacteristicSetValue(@RpcParameter(name = "gattIndex") Integer gattIndex, 571 @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, 572 @RpcParameter(name = "serviceIndex") Integer serviceIndex, 573 @RpcParameter(name = "characteristicUuid") String characteristicUuid, 574 @RpcParameter(name = "value") byte[] value) throws Exception { 575 if (mBluetoothGattList.get(gattIndex) == null) { 576 throw new Exception("Invalid gattIndex " + gattIndex); 577 } 578 List<BluetoothGattService> discoveredServiceList = 579 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex); 580 if (discoveredServiceList == null) { 581 throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex); 582 } 583 BluetoothGattService gattService = discoveredServiceList.get(serviceIndex); 584 if (gattService == null) { 585 throw new Exception("Invalid serviceIndex " + serviceIndex); 586 } 587 UUID cUuid = UUID.fromString(characteristicUuid); 588 BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid); 589 if (gattCharacteristic == null) { 590 throw new Exception("Invalid characteristic uuid: " + characteristicUuid); 591 } 592 return gattCharacteristic.setValue(value); 593 } 594 595 /** 596 * Set write type to a discovered characteristic. 597 * @param gattIndex - the gatt index to use 598 * @param discoveredServiceListIndex - the discovered service list index 599 * @param serviceIndex - the service index of the discoveredServiceListIndex 600 * @param characteristicUuid - the characteristic uuid in which the descriptor is 601 * @param writeType - the write type for characteristic 602 * @return true, if the value was set to the characteristic 603 * @throws Exception 604 */ 605 @Rpc(description = "Set write type of a given characteristic to the associated remote device") gattClientCharacteristicSetWriteType( @pcParametername = "gattIndex") Integer gattIndex, @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid, @RpcParameter(name = "writeType") Integer writeType)606 public boolean gattClientCharacteristicSetWriteType( 607 @RpcParameter(name = "gattIndex") Integer gattIndex, 608 @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, 609 @RpcParameter(name = "serviceIndex") Integer serviceIndex, 610 @RpcParameter(name = "characteristicUuid") String characteristicUuid, 611 @RpcParameter(name = "writeType") Integer writeType) throws Exception { 612 if (mBluetoothGattList.get(gattIndex) == null) { 613 throw new Exception("Invalid gattIndex " + gattIndex); 614 } 615 List<BluetoothGattService> discoveredServiceList = 616 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex); 617 if (discoveredServiceList == null) { 618 throw new Exception("Invalid discoveredServiceListIndex " + discoveredServiceListIndex); 619 } 620 BluetoothGattService gattService = discoveredServiceList.get(serviceIndex); 621 if (gattService == null) { 622 throw new Exception("Invalid serviceIndex " + serviceIndex); 623 } 624 UUID cUuid = UUID.fromString(characteristicUuid); 625 BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(cUuid); 626 if (gattCharacteristic == null) { 627 throw new Exception("Invalid characteristic uuid: " + characteristicUuid); 628 } 629 gattCharacteristic.setWriteType(writeType); 630 return true; 631 } 632 633 /** 634 * Read the RSSI for a connected remote device 635 * 636 * @param index the bluetooth gatt index 637 * @return true, if the RSSI value has been requested successfully 638 * @throws Exception 639 */ 640 @Rpc(description = "Read the RSSI for a connected remote device") gattClientReadRSSI( @pcParametername = "index") Integer index )641 public boolean gattClientReadRSSI( 642 @RpcParameter(name = "index") 643 Integer index 644 ) throws Exception { 645 if (mBluetoothGattList.get(index) != null) { 646 return mBluetoothGattList.get(index).readRemoteRssi(); 647 } else { 648 throw new Exception("Invalid index input:" + index); 649 } 650 } 651 652 /** 653 * Clears the internal cache and forces a refresh of the services from the remote device 654 * 655 * @param index the bluetooth gatt index 656 * @return Clears the internal cache and forces a refresh of the services from the remote 657 * device. 658 * @throws Exception 659 */ 660 @Rpc(description = "Clears the internal cache and forces a refresh of the services from the remote device") gattClientRefresh( @pcParametername = "index") Integer index )661 public boolean gattClientRefresh( 662 @RpcParameter(name = "index") 663 Integer index 664 ) throws Exception { 665 if (mBluetoothGattList.get(index) != null) { 666 return mBluetoothGattList.get(index).refresh(); 667 } else { 668 throw new Exception("Invalid index input:" + index); 669 } 670 } 671 672 /** 673 * Request a connection parameter update. 674 * @param index the bluetooth gatt index 675 * @param connectionPriority connection priority 676 * @return boolean True if successful False otherwise. 677 * @throws Exception 678 */ 679 @Rpc(description = "Request a connection parameter update. from the Bluetooth Gatt") gattClientRequestConnectionPriority( @pcParametername = "index") Integer index, @RpcParameter(name = "connectionPriority") Integer connectionPriority )680 public boolean gattClientRequestConnectionPriority( 681 @RpcParameter(name = "index") 682 Integer index, 683 @RpcParameter(name = "connectionPriority") 684 Integer connectionPriority 685 ) throws Exception { 686 boolean result = false; 687 if (mBluetoothGattList.get(index) != null) { 688 result = mBluetoothGattList.get(index).requestConnectionPriority( 689 connectionPriority); 690 } else { 691 throw new Exception("Invalid index input:" + index); 692 } 693 return result; 694 } 695 696 /** 697 * Sets the characteristic notification of a bluetooth gatt 698 * 699 * @param index the bluetooth gatt index 700 * @param characteristicIndex the characteristic index 701 * @param enable Enable or disable notifications/indications for a given characteristic 702 * @return true, if the requested notification status was set successfully 703 * @throws Exception 704 */ 705 @Rpc(description = "Sets the characteristic notification of a bluetooth gatt") gattClientSetCharacteristicNotification( @pcParametername = "gattIndex") Integer gattIndex, @RpcParameter(name = "discoveredServiceListIndex") Integer discoveredServiceListIndex, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid, @RpcParameter(name = "enable") Boolean enable )706 public boolean gattClientSetCharacteristicNotification( 707 @RpcParameter(name = "gattIndex") 708 Integer gattIndex, 709 @RpcParameter(name = "discoveredServiceListIndex") 710 Integer discoveredServiceListIndex, 711 @RpcParameter(name = "serviceIndex") 712 Integer serviceIndex, 713 @RpcParameter(name = "characteristicUuid") 714 String characteristicUuid, 715 @RpcParameter(name = "enable") 716 Boolean enable 717 ) throws Exception { 718 if (mBluetoothGattList.get(gattIndex) != null) { 719 if(mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex) != null) { 720 List<BluetoothGattService> discoveredServiceList = 721 mBluetoothGattDiscoveredServicesList.get(discoveredServiceListIndex); 722 if (discoveredServiceList.get(serviceIndex) != null) { 723 UUID cUuid = UUID.fromString(characteristicUuid); 724 if (discoveredServiceList.get(serviceIndex).getCharacteristic(cUuid) != null) { 725 return mBluetoothGattList.get(gattIndex).setCharacteristicNotification( 726 discoveredServiceList.get(serviceIndex).getCharacteristic(cUuid), enable); 727 } else { 728 throw new Exception ("Invalid characteristic uuid: " + characteristicUuid); 729 } 730 } else { 731 throw new Exception ("Invalid serviceIndex " + serviceIndex); 732 } 733 } else { 734 throw new Exception("Invalid discoveredServiceListIndex: " + discoveredServiceListIndex); 735 } 736 } else { 737 throw new Exception("Invalid gattIndex input: " + gattIndex); 738 } 739 } 740 741 /** 742 * Create a new GattCallback object 743 * 744 * @return the index of the callback object 745 */ 746 @Rpc(description = "Create a new GattCallback object") gattCreateGattCallback()747 public Integer gattCreateGattCallback() { 748 GattCallbackCount += 1; 749 int index = GattCallbackCount; 750 mGattCallbackList.put(index, new myBluetoothGattCallback(index)); 751 return index; 752 } 753 754 /** 755 * Returns the list of discovered Bluetooth Gatt Services. 756 * @throws Exception 757 */ 758 @Rpc(description = "Get Bluetooth Gatt Services") gattClientGetDiscoveredServicesCount( @pcParametername = "index") Integer index )759 public int gattClientGetDiscoveredServicesCount ( 760 @RpcParameter(name = "index") 761 Integer index 762 ) throws Exception { 763 if (mBluetoothGattDiscoveredServicesList.get(index) != null) { 764 return mBluetoothGattDiscoveredServicesList.get(index).size(); 765 } else { 766 throw new Exception("Invalid index input:" + index); 767 } 768 } 769 770 /** 771 * Returns the discovered Bluetooth Gatt Service Uuid. 772 * @throws Exception 773 */ 774 @Rpc(description = "Get Bluetooth Gatt Service Uuid") gattClientGetDiscoveredServiceUuid( @pcParametername = "index") Integer index, @RpcParameter(name = "serviceIndex") Integer serviceIndex )775 public String gattClientGetDiscoveredServiceUuid ( 776 @RpcParameter(name = "index") 777 Integer index, 778 @RpcParameter(name = "serviceIndex") 779 Integer serviceIndex 780 ) throws Exception { 781 List<BluetoothGattService> mBluetoothServiceList = 782 mBluetoothGattDiscoveredServicesList.get(index); 783 if (mBluetoothServiceList != null) { 784 return mBluetoothServiceList.get(serviceIndex).getUuid().toString(); 785 } else { 786 throw new Exception("Invalid index input:" + index); 787 } 788 } 789 790 /** 791 * Get discovered characteristic uuids from the pheripheral device. 792 * @param index the index of the bluetooth gatt discovered services list 793 * @param serviceIndex the service to get 794 * @return the list of characteristic uuids 795 * @throws Exception 796 */ 797 @Rpc(description = "Get Bluetooth Gatt Services") gattClientGetDiscoveredCharacteristicUuids( @pcParametername = "index") Integer index, @RpcParameter(name = "serviceIndex") Integer serviceIndex )798 public ArrayList<String> gattClientGetDiscoveredCharacteristicUuids ( 799 @RpcParameter(name = "index") 800 Integer index, 801 @RpcParameter(name = "serviceIndex") 802 Integer serviceIndex 803 ) throws Exception { 804 if (mBluetoothGattDiscoveredServicesList.get(index) != null) { 805 if (mBluetoothGattDiscoveredServicesList.get(index).get(serviceIndex) != null) { 806 ArrayList<String> uuidList = new ArrayList<String>(); 807 List<BluetoothGattCharacteristic> charList = mBluetoothGattDiscoveredServicesList.get(index).get(serviceIndex).getCharacteristics(); 808 for (BluetoothGattCharacteristic mChar : charList) { 809 uuidList.add(mChar.getUuid().toString()); 810 } 811 return uuidList; 812 } else { 813 throw new Exception("Invalid serviceIndex input:" + index); 814 } 815 } else { 816 throw new Exception("Invalid index input:" + index); 817 } 818 } 819 820 /** 821 * Get discovered descriptor uuids from the pheripheral device. 822 * @param index the discovered services list index 823 * @param serviceIndex the service index of the discovered services list 824 * @param characteristicUuid the characteristicUuid to select from the 825 * discovered service which contains the list of descriptors. 826 * @return the list of descriptor uuids 827 * @throws Exception 828 */ 829 @Rpc(description = "Get Bluetooth Gatt Services") gattClientGetDiscoveredDescriptorUuids( @pcParametername = "index") Integer index, @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "characteristicUuid") String characteristicUuid )830 public ArrayList<String> gattClientGetDiscoveredDescriptorUuids ( 831 @RpcParameter(name = "index") 832 Integer index, 833 @RpcParameter(name = "serviceIndex") 834 Integer serviceIndex, 835 @RpcParameter(name = "characteristicUuid") 836 String characteristicUuid 837 ) throws Exception { 838 if (mBluetoothGattDiscoveredServicesList.get(index) != null) { 839 if (mBluetoothGattDiscoveredServicesList.get(index).get(serviceIndex) != null) { 840 BluetoothGattService service = mBluetoothGattDiscoveredServicesList.get(index).get(serviceIndex); 841 UUID cUuid = UUID.fromString(characteristicUuid); 842 if (service.getCharacteristic(cUuid) != null) { 843 ArrayList<String> uuidList = new ArrayList<String>(); 844 for (BluetoothGattDescriptor mDesc : service.getCharacteristic(cUuid).getDescriptors()) { 845 uuidList.add(mDesc.getUuid().toString()); 846 } 847 return uuidList; 848 } else { 849 throw new Exception("Invalid characeristicUuid : " 850 + characteristicUuid); 851 } 852 } else { 853 throw new Exception("Invalid serviceIndex input:" 854 + index); 855 } 856 } else { 857 throw new Exception("Invalid index input:" 858 + index); 859 } 860 } 861 862 private class myBluetoothGattCallback extends BluetoothGattCallback { 863 private final Bundle mResults; 864 private final int index; 865 private final String mEventType; 866 myBluetoothGattCallback(int idx)867 public myBluetoothGattCallback(int idx) { 868 mResults = new Bundle(); 869 mEventType = "GattConnect"; 870 index = idx; 871 } 872 873 @Override onConnectionStateChange(BluetoothGatt gatt, int status, int newState)874 public void onConnectionStateChange(BluetoothGatt gatt, int status, 875 int newState) { 876 Log.d("gatt_connect change onConnectionStateChange " + mEventType + " " + index); 877 if (newState == BluetoothProfile.STATE_CONNECTED) { 878 Log.d("State Connected to mac address " 879 + gatt.getDevice().getAddress() + " status " + status); 880 } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { 881 Log.d("State Disconnected from mac address " 882 + gatt.getDevice().getAddress() + " status " + status); 883 } else if (newState == BluetoothProfile.STATE_CONNECTING) { 884 Log.d("State Connecting to mac address " 885 + gatt.getDevice().getAddress() + " status " + status); 886 } else if (newState == BluetoothProfile.STATE_DISCONNECTING) { 887 Log.d("State Disconnecting from mac address " 888 + gatt.getDevice().getAddress() + " status " + status); 889 } 890 mResults.putInt("Status", status); 891 mResults.putInt("State", newState); 892 mEventFacade 893 .postEvent(mEventType + index + "onConnectionStateChange", mResults.clone()); 894 mResults.clear(); 895 } 896 897 @Override onServicesDiscovered(BluetoothGatt gatt, int status)898 public void onServicesDiscovered(BluetoothGatt gatt, int status) { 899 Log.d("gatt_connect change onServicesDiscovered " + mEventType + " " + index); 900 int idx = BluetoothGattDiscoveredServicesCount++; 901 mBluetoothGattDiscoveredServicesList.put(idx, gatt.getServices()); 902 mResults.putInt("ServicesIndex", idx); 903 mResults.putInt("Status", status); 904 for (BluetoothGattService se: gatt.getServices()) { 905 System.out.println("SWAG: " + se.getUuid().toString()); 906 } 907 mEventFacade 908 .postEvent(mEventType + index + "onServicesDiscovered", mResults.clone()); 909 mResults.clear(); 910 } 911 912 @Override onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)913 public void onCharacteristicRead(BluetoothGatt gatt, 914 BluetoothGattCharacteristic characteristic, 915 int status) { 916 Log.d("gatt_connect change onCharacteristicRead " + mEventType + " " + index); 917 mResults.putInt("Status", status); 918 mResults.putString("CharacteristicUuid", characteristic.getUuid().toString()); 919 mResults.putByteArray("CharacteristicValue", characteristic.getValue()); 920 mEventFacade 921 .postEvent(mEventType + index + "onCharacteristicRead", mResults.clone()); 922 mResults.clear(); 923 } 924 925 @Override onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)926 public void onCharacteristicWrite(BluetoothGatt gatt, 927 BluetoothGattCharacteristic characteristic, int status) { 928 Log.d("gatt_connect change onCharacteristicWrite " + mEventType + " " + index); 929 mResults.putInt("Status", status); 930 mResults.putString("CharacteristicUuid", characteristic.getUuid().toString()); 931 mResults.putByteArray("CharacteristicValue", characteristic.getValue()); 932 mEventFacade 933 .postEvent(mEventType + index + "onCharacteristicWrite", mResults.clone()); 934 mResults.clear(); 935 } 936 937 @Override onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)938 public void onCharacteristicChanged(BluetoothGatt gatt, 939 BluetoothGattCharacteristic characteristic) { 940 Log.d("gatt_connect change onCharacteristicChanged " + mEventType + " " + index); 941 mResults.putInt("ID", index); 942 mResults.putString("CharacteristicUuid", characteristic.getUuid().toString()); 943 mResults.putByteArray("CharacteristicValue", characteristic.getValue()); 944 mEventFacade 945 .postEvent(mEventType + index + "onCharacteristicChanged", mResults.clone()); 946 mResults.clear(); 947 } 948 949 @Override onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status)950 public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, 951 int status) { 952 Log.d("gatt_connect change onServicesDiscovered " + mEventType + " " + index); 953 mResults.putInt("Status", status); 954 mResults.putString("DescriptorUuid", descriptor.getUuid().toString()); 955 mEventFacade 956 .postEvent(mEventType + index + "onDescriptorRead", mResults.clone()); 957 mResults.clear(); 958 } 959 960 @Override onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status)961 public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, 962 int status) { 963 Log.d("gatt_connect change onDescriptorWrite " + mEventType + " " + index); 964 mResults.putInt("ID", index); 965 mResults.putInt("Status", status); 966 mResults.putString("DescriptorUuid", descriptor.getUuid().toString()); 967 mEventFacade 968 .postEvent(mEventType + index + "onDescriptorWrite", mResults.clone()); 969 mResults.clear(); 970 } 971 972 @Override onReliableWriteCompleted(BluetoothGatt gatt, int status)973 public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { 974 Log.d("gatt_connect change onReliableWriteCompleted " + mEventType + " " 975 + index); 976 mResults.putInt("Status", status); 977 mEventFacade 978 .postEvent(mEventType + index + "onReliableWriteCompleted", mResults.clone()); 979 mResults.clear(); 980 } 981 982 @Override onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status)983 public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { 984 Log.d("gatt_connect change onReadRemoteRssi " + mEventType + " " + index); 985 mResults.putInt("Status", status); 986 mResults.putInt("Rssi", rssi); 987 mEventFacade 988 .postEvent(mEventType + index + "onReadRemoteRssi", mResults.clone()); 989 mResults.clear(); 990 } 991 992 @Override onMtuChanged(BluetoothGatt gatt, int mtu, int status)993 public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { 994 Log.d("gatt_connect change onMtuChanged " + mEventType + " " + index); 995 mResults.putInt("Status", status); 996 mResults.putInt("MTU", mtu); 997 mEventFacade 998 .postEvent(mEventType + index + "onMtuChanged", mResults.clone()); 999 mResults.clear(); 1000 } 1001 } 1002 1003 @Override shutdown()1004 public void shutdown() { 1005 if (!mBluetoothGattList.isEmpty()) { 1006 if (mBluetoothGattList.values() != null) { 1007 for (BluetoothGatt mBluetoothGatt : mBluetoothGattList.values()) { 1008 mBluetoothGatt.close(); 1009 } 1010 } 1011 } 1012 mGattCallbackList.clear(); 1013 } 1014 } 1015