1 /* 2 * Copyright (C) 2017 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 17 package com.googlecode.android_scripting.facade.bluetooth; 18 19 import android.app.Service; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothAdapter.LeScanCallback; 22 import android.bluetooth.BluetoothDevice; 23 import android.bluetooth.le.BluetoothLeScanner; 24 import android.bluetooth.le.ScanCallback; 25 import android.bluetooth.le.ScanFilter; 26 import android.bluetooth.le.ScanFilter.Builder; 27 import android.bluetooth.le.ScanResult; 28 import android.bluetooth.le.ScanSettings; 29 import android.os.Bundle; 30 import android.os.ParcelUuid; 31 32 import com.googlecode.android_scripting.Log; 33 import com.googlecode.android_scripting.MainThread; 34 import com.googlecode.android_scripting.facade.EventFacade; 35 import com.googlecode.android_scripting.facade.FacadeManager; 36 import com.googlecode.android_scripting.jsonrpc.RpcReceiver; 37 import com.googlecode.android_scripting.rpc.Rpc; 38 import com.googlecode.android_scripting.rpc.RpcOptional; 39 import com.googlecode.android_scripting.rpc.RpcParameter; 40 41 import java.util.ArrayList; 42 import java.util.HashMap; 43 import java.util.List; 44 import java.util.UUID; 45 import java.util.concurrent.Callable; 46 47 /** 48 * BluetoothLe Scan functions. 49 */ 50 51 public class BluetoothLeScanFacade extends RpcReceiver { 52 53 private final EventFacade mEventFacade; 54 55 private BluetoothAdapter mBluetoothAdapter; 56 private static int ScanCallbackCount; 57 private static int FilterListCount; 58 private static int LeScanCallbackCount; 59 private static int ScanSettingsCount; 60 private final Service mService; 61 private final BluetoothLeScanner mScanner; 62 private android.bluetooth.le.ScanSettings.Builder mScanSettingsBuilder; 63 private Builder mScanFilterBuilder; 64 private final HashMap<Integer, myScanCallback> mScanCallbackList; 65 private final HashMap<Integer, myLeScanCallback> mLeScanCallbackList; 66 private final HashMap<Integer, ArrayList<ScanFilter>> mScanFilterList; 67 private final HashMap<Integer, ScanSettings> mScanSettingsList; 68 69 public BluetoothLeScanFacade(FacadeManager manager) { 70 super(manager); 71 mService = manager.getService(); 72 mBluetoothAdapter = MainThread.run(mService, 73 new Callable<BluetoothAdapter>() { 74 @Override 75 public BluetoothAdapter call() throws Exception { 76 return BluetoothAdapter.getDefaultAdapter(); 77 } 78 }); 79 mScanner = mBluetoothAdapter.getBluetoothLeScanner(); 80 mEventFacade = manager.getReceiver(EventFacade.class); 81 mScanFilterList = new HashMap<Integer, ArrayList<ScanFilter>>(); 82 mLeScanCallbackList = new HashMap<Integer, myLeScanCallback>(); 83 mScanSettingsList = new HashMap<Integer, ScanSettings>(); 84 mScanCallbackList = new HashMap<Integer, myScanCallback>(); 85 mScanFilterBuilder = new Builder(); 86 mScanSettingsBuilder = new android.bluetooth.le.ScanSettings.Builder(); 87 } 88 89 /** 90 * Constructs a myScanCallback obj and returns its index 91 * 92 * @return Integer myScanCallback.index 93 */ 94 @Rpc(description = "Generate a new myScanCallback Object") 95 public Integer bleGenScanCallback() { 96 ScanCallbackCount += 1; 97 int index = ScanCallbackCount; 98 myScanCallback mScan = new myScanCallback(index); 99 mScanCallbackList.put(mScan.index, mScan); 100 return mScan.index; 101 } 102 103 /** 104 * Constructs a myLeScanCallback obj and returns its index 105 * 106 * @return Integer myScanCallback.index 107 */ 108 @Rpc(description = "Generate a new myScanCallback Object") 109 public Integer bleGenLeScanCallback() { 110 LeScanCallbackCount += 1; 111 int index = LeScanCallbackCount; 112 myLeScanCallback mScan = new myLeScanCallback(index); 113 mLeScanCallbackList.put(mScan.index, mScan); 114 return mScan.index; 115 } 116 117 /** 118 * Constructs a new filter list array and returns its index 119 * 120 * @return Integer index 121 */ 122 @Rpc(description = "Generate a new Filter list") 123 public Integer bleGenFilterList() { 124 FilterListCount += 1; 125 int index = FilterListCount; 126 mScanFilterList.put(index, new ArrayList<ScanFilter>()); 127 return index; 128 } 129 130 /** 131 * Constructs a new filter list array and returns its index 132 * 133 * @return Integer index 134 */ 135 @Rpc(description = "Generate a new Filter list") 136 public Integer bleBuildScanFilter( 137 @RpcParameter(name = "filterIndex") 138 Integer filterIndex 139 ) { 140 mScanFilterList.get(filterIndex).add(mScanFilterBuilder.build()); 141 mScanFilterBuilder = new Builder(); 142 return mScanFilterList.get(filterIndex).size()-1; 143 } 144 145 /** 146 * Constructs a new scan setting and returns its index 147 * 148 * @return Integer index 149 */ 150 @Rpc(description = "Generate a new scan settings Object") 151 public Integer bleBuildScanSetting() { 152 ScanSettingsCount += 1; 153 int index = ScanSettingsCount; 154 mScanSettingsList.put(index, mScanSettingsBuilder.build()); 155 mScanSettingsBuilder = new android.bluetooth.le.ScanSettings.Builder(); 156 return index; 157 } 158 159 /** 160 * Stops a ble scan 161 * 162 * @param index the id of the myScan whose ScanCallback to stop 163 * @throws Exception 164 */ 165 @Rpc(description = "Stops an ongoing ble advertisement scan") 166 public void bleStopBleScan( 167 @RpcParameter(name = "index") 168 Integer index) throws Exception { 169 Log.d("bluetooth_le_scan mScanCallback " + index); 170 if (mScanCallbackList.get(index) != null) { 171 myScanCallback mScanCallback = mScanCallbackList.get(index); 172 mScanner.stopScan(mScanCallback); 173 } else { 174 throw new Exception("Invalid index input:" + Integer.toString(index)); 175 } 176 } 177 178 /** 179 * Stops a classic ble scan 180 * 181 * @param index the id of the myScan whose LeScanCallback to stop 182 * @throws Exception 183 */ 184 @Rpc(description = "Stops an ongoing classic ble scan") 185 public void bleStopClassicBleScan( 186 @RpcParameter(name = "index") 187 Integer index) throws Exception { 188 Log.d("bluetooth_le_scan mLeScanCallback " + index); 189 if (mLeScanCallbackList.get(index) != null) { 190 myLeScanCallback mLeScanCallback = mLeScanCallbackList.get(index); 191 mBluetoothAdapter.stopLeScan(mLeScanCallback); 192 } else { 193 throw new Exception("Invalid index input:" + Integer.toString(index)); 194 } 195 } 196 197 /** 198 * Starts a ble scan 199 * 200 * @param index the id of the myScan whose ScanCallback to start 201 * @throws Exception 202 */ 203 @Rpc(description = "Starts a ble advertisement scan") 204 public void bleStartBleScan( 205 @RpcParameter(name = "filterListIndex") 206 Integer filterListIndex, 207 @RpcParameter(name = "scanSettingsIndex") 208 Integer scanSettingsIndex, 209 @RpcParameter(name = "callbackIndex") 210 Integer callbackIndex 211 ) throws Exception { 212 Log.d("bluetooth_le_scan starting a background scan"); 213 ArrayList<ScanFilter> mScanFilters = new ArrayList<ScanFilter>(); 214 mScanFilters.add(new ScanFilter.Builder().build()); 215 ScanSettings mScanSettings = new ScanSettings.Builder().build(); 216 if (mScanFilterList.get(filterListIndex) != null) { 217 mScanFilters = mScanFilterList.get(filterListIndex); 218 } else { 219 throw new Exception("Invalid filterListIndex input:" 220 + Integer.toString(filterListIndex)); 221 } 222 if (mScanSettingsList.get(scanSettingsIndex) != null) { 223 mScanSettings = mScanSettingsList.get(scanSettingsIndex); 224 } else if (!mScanSettingsList.isEmpty()) { 225 throw new Exception("Invalid scanSettingsIndex input:" 226 + Integer.toString(scanSettingsIndex)); 227 } 228 if (mScanCallbackList.get(callbackIndex) != null) { 229 mScanner.startScan(mScanFilters, mScanSettings, 230 mScanCallbackList.get(callbackIndex)); 231 } else { 232 throw new Exception("Invalid filterListIndex input:" 233 + Integer.toString(filterListIndex)); 234 } 235 } 236 237 /** 238 * Starts a classic ble scan 239 * 240 * @param index the id of the myScan whose ScanCallback to start 241 * @throws Exception 242 */ 243 @Rpc(description = "Starts a classic ble advertisement scan") 244 public boolean bleStartClassicBleScan( 245 @RpcParameter(name = "leCallbackIndex") 246 Integer leCallbackIndex 247 ) throws Exception { 248 Log.d("bluetooth_le_scan starting a background scan"); 249 boolean result = false; 250 if (mLeScanCallbackList.get(leCallbackIndex) != null) { 251 result = mBluetoothAdapter.startLeScan( 252 mLeScanCallbackList.get(leCallbackIndex)); 253 } else { 254 throw new Exception("Invalid leCallbackIndex input:" 255 + Integer.toString(leCallbackIndex)); 256 } 257 return result; 258 } 259 260 /** 261 * Starts a classic ble scan with service Uuids 262 * 263 * @param index the id of the myScan whose ScanCallback to start 264 * @throws Exception 265 */ 266 @Rpc(description = "Starts a classic ble advertisement scan with service Uuids") 267 public boolean bleStartClassicBleScanWithServiceUuids( 268 @RpcParameter(name = "leCallbackIndex") 269 Integer leCallbackIndex, 270 @RpcParameter(name = "serviceUuids") 271 String[] serviceUuidList 272 ) throws Exception { 273 Log.d("bluetooth_le_scan starting a background scan"); 274 UUID[] serviceUuids = new UUID[serviceUuidList.length]; 275 for (int i = 0; i < serviceUuidList.length; i++) { 276 serviceUuids[i] = UUID.fromString(serviceUuidList[i]); 277 } 278 boolean result = false; 279 if (mLeScanCallbackList.get(leCallbackIndex) != null) { 280 result = mBluetoothAdapter.startLeScan(serviceUuids, 281 mLeScanCallbackList.get(leCallbackIndex)); 282 } else { 283 throw new Exception("Invalid leCallbackIndex input:" 284 + Integer.toString(leCallbackIndex)); 285 } 286 return result; 287 } 288 289 /** 290 * Trigger onBatchScanResults 291 * 292 * @throws Exception 293 */ 294 @Rpc(description = "Gets the results of the ble ScanCallback") 295 public void bleFlushPendingScanResults( 296 @RpcParameter(name = "callbackIndex") 297 Integer callbackIndex 298 ) throws Exception { 299 if (mScanCallbackList.get(callbackIndex) != null) { 300 mBluetoothAdapter 301 .getBluetoothLeScanner().flushPendingScanResults( 302 mScanCallbackList.get(callbackIndex)); 303 } else { 304 throw new Exception("Invalid callbackIndex input:" 305 + Integer.toString(callbackIndex)); 306 } 307 } 308 309 /** 310 * Set scanSettings for ble scan. Note: You have to set all variables at once. 311 * 312 * @param callbackType Bluetooth LE scan callback type 313 * @param reportDelaySeconds Time of delay for reporting the scan result 314 * @param scanMode Bluetooth LE scan mode. 315 * @param scanResultType Bluetooth LE scan result type 316 * @throws Exception 317 */ 318 319 /** 320 * Set the scan setting's callback type 321 * @param callbackType Bluetooth LE scan callback type 322 */ 323 @Rpc(description = "Set the scan setting's callback type") 324 public void bleSetScanSettingsCallbackType( 325 @RpcParameter(name = "callbackType") 326 Integer callbackType) { 327 mScanSettingsBuilder.setCallbackType(callbackType); 328 } 329 330 /** 331 * Set the scan setting's report delay millis 332 * @param reportDelayMillis Time of delay for reporting the scan result 333 */ 334 @Rpc(description = "Set the scan setting's report delay millis") 335 public void bleSetScanSettingsReportDelayMillis( 336 @RpcParameter(name = "reportDelayMillis") 337 Long reportDelayMillis) { 338 mScanSettingsBuilder.setReportDelay(reportDelayMillis); 339 } 340 341 /** 342 * Set the scan setting's scan mode 343 * @param scanMode Bluetooth LE scan mode. 344 */ 345 @Rpc(description = "Set the scan setting's scan mode") 346 public void bleSetScanSettingsScanMode( 347 @RpcParameter(name = "scanMode") 348 Integer scanMode) { 349 mScanSettingsBuilder.setScanMode(scanMode); 350 } 351 352 /** 353 * Set the scan setting's legacy mode 354 * @param legacy Wether scan is legacy. 355 */ 356 @Rpc(description = "Set the scan setting's legacy mode") 357 public void bleSetScanSettingsLegacy( 358 @RpcParameter(name = "legacy") 359 Boolean legacy) { 360 mScanSettingsBuilder.setLegacy(legacy); 361 } 362 363 /** 364 * Set the scan setting's phy mode 365 * @param phy 366 */ 367 @Rpc(description = "Set the scan setting's phy mode") 368 public void bleSetScanSettingsPhy( 369 @RpcParameter(name = "phy") 370 Integer phy) { 371 mScanSettingsBuilder.setPhy(phy); 372 } 373 374 /** 375 * Set the scan setting's scan result type 376 * @param scanResultType Bluetooth LE scan result type 377 */ 378 @Rpc(description = "Set the scan setting's scan result type") 379 public void bleSetScanSettingsResultType( 380 @RpcParameter(name = "scanResultType") 381 Integer scanResultType) { 382 mScanSettingsBuilder.setScanResultType(scanResultType); 383 } 384 /** 385 * Get ScanSetting's callback type 386 * 387 * @param index the ScanSetting object to use 388 * @return the ScanSetting's callback type 389 * @throws Exception 390 */ 391 @Rpc(description = "Get ScanSetting's callback type") 392 public Integer bleGetScanSettingsCallbackType( 393 @RpcParameter(name = "index") 394 Integer index 395 ) throws Exception { 396 if (mScanSettingsList.get(index) != null) { 397 ScanSettings mScanSettings = mScanSettingsList.get(index); 398 return mScanSettings.getCallbackType(); 399 } else { 400 throw new Exception("Invalid index input:" + Integer.toString(index)); 401 } 402 } 403 404 /** 405 * Get ScanSetting's report delay in milli seconds 406 * 407 * @param index the ScanSetting object to useSystemClock 408 * @return the ScanSetting's report delay in milliseconds 409 * @throws Exception 410 */ 411 @Rpc(description = "Get ScanSetting's report delay milliseconds") 412 public Long bleGetScanSettingsReportDelayMillis( 413 @RpcParameter(name = "index") 414 Integer index) throws Exception { 415 if (mScanSettingsList.get(index) != null) { 416 ScanSettings mScanSettings = mScanSettingsList.get(index); 417 return mScanSettings.getReportDelayMillis(); 418 } else { 419 throw new Exception("Invalid index input:" + Integer.toString(index)); 420 } 421 } 422 423 /** 424 * Get ScanSetting's scan mode 425 * 426 * @param index the ScanSetting object to use 427 * @return the ScanSetting's scan mode 428 * @throws Exception 429 */ 430 @Rpc(description = "Get ScanSetting's scan mode") 431 public Integer bleGetScanSettingsScanMode( 432 @RpcParameter(name = "index") 433 Integer index) throws Exception { 434 if (mScanSettingsList.get(index) != null) { 435 ScanSettings mScanSettings = mScanSettingsList.get(index); 436 return mScanSettings.getScanMode(); 437 } else { 438 throw new Exception("Invalid index input:" + Integer.toString(index)); 439 } 440 } 441 442 /** 443 * Get ScanSetting's scan result type 444 * 445 * @param index the ScanSetting object to use 446 * @return the ScanSetting's scan result type 447 * @throws Exception 448 */ 449 @Rpc(description = "Get ScanSetting's scan result type") 450 public Integer bleGetScanSettingsScanResultType( 451 @RpcParameter(name = "index") 452 Integer index) throws Exception { 453 if (mScanSettingsList.get(index) != null) { 454 ScanSettings mScanSettings = mScanSettingsList.get(index); 455 return mScanSettings.getScanResultType(); 456 } else { 457 throw new Exception("Invalid index input:" 458 + Integer.toString(index)); 459 } 460 } 461 462 /** 463 * Get ScanFilter's Manufacturer Id 464 * 465 * @param index the ScanFilter object to use 466 * @return the ScanFilter's manufacturer id 467 * @throws Exception 468 */ 469 @Rpc(description = "Get ScanFilter's Manufacturer Id") 470 public Integer bleGetScanFilterManufacturerId( 471 @RpcParameter(name = "index") 472 Integer index, 473 @RpcParameter(name = "filterIndex") 474 Integer filterIndex) 475 throws Exception { 476 if (mScanFilterList.get(index) != null) { 477 if (mScanFilterList.get(index).get(filterIndex) != null) { 478 return mScanFilterList.get(index) 479 .get(filterIndex).getManufacturerId(); 480 } else { 481 throw new Exception("Invalid filterIndex input:" 482 + Integer.toString(filterIndex)); 483 } 484 } else { 485 throw new Exception("Invalid index input:" 486 + Integer.toString(index)); 487 } 488 } 489 490 /** 491 * Get ScanFilter's device address 492 * 493 * @param index the ScanFilter object to use 494 * @return the ScanFilter's device address 495 * @throws Exception 496 */ 497 @Rpc(description = "Get ScanFilter's device address") 498 public String bleGetScanFilterDeviceAddress( 499 @RpcParameter(name = "index") 500 Integer index, 501 @RpcParameter(name = "filterIndex") 502 Integer filterIndex) 503 throws Exception { 504 if (mScanFilterList.get(index) != null) { 505 if (mScanFilterList.get(index).get(filterIndex) != null) { 506 return mScanFilterList.get(index).get( 507 filterIndex).getDeviceAddress(); 508 } else { 509 throw new Exception("Invalid filterIndex input:" 510 + Integer.toString(filterIndex)); 511 } 512 } else { 513 throw new Exception("Invalid index input:" 514 + Integer.toString(index)); 515 } 516 } 517 518 /** 519 * Get ScanFilter's device name 520 * 521 * @param index the ScanFilter object to use 522 * @return the ScanFilter's device name 523 * @throws Exception 524 */ 525 @Rpc(description = "Get ScanFilter's device name") 526 public String bleGetScanFilterDeviceName( 527 @RpcParameter(name = "index") 528 Integer index, 529 @RpcParameter(name = "filterIndex") 530 Integer filterIndex) 531 throws Exception { 532 if (mScanFilterList.get(index) != null) { 533 if (mScanFilterList.get(index).get(filterIndex) != null) { 534 return mScanFilterList.get(index).get( 535 filterIndex).getDeviceName(); 536 } else { 537 throw new Exception("Invalid filterIndex input:" 538 + Integer.toString(filterIndex)); 539 } 540 } else { 541 throw new Exception("Invalid index input:" 542 + Integer.toString(index)); 543 } 544 } 545 546 /** 547 * Get ScanFilter's manufacturer data 548 * 549 * @param index the ScanFilter object to use 550 * @return the ScanFilter's manufacturer data 551 * @throws Exception 552 */ 553 @Rpc(description = "Get ScanFilter's manufacturer data") 554 public byte[] bleGetScanFilterManufacturerData( 555 @RpcParameter(name = "index") 556 Integer index, 557 @RpcParameter(name = "filterIndex") 558 Integer filterIndex) 559 throws Exception { 560 if (mScanFilterList.get(index) != null) { 561 if (mScanFilterList.get(index).get(filterIndex) != null) { 562 return mScanFilterList.get(index).get( 563 filterIndex).getManufacturerData(); 564 } else { 565 throw new Exception("Invalid filterIndex input:" 566 + Integer.toString(filterIndex)); 567 } 568 } else { 569 throw new Exception("Invalid index input:" 570 + Integer.toString(index)); 571 } 572 } 573 574 /** 575 * Get ScanFilter's manufacturer data mask 576 * 577 * @param index the ScanFilter object to use 578 * @return the ScanFilter's manufacturer data mask 579 * @throws Exception 580 */ 581 @Rpc(description = "Get ScanFilter's manufacturer data mask") 582 public byte[] bleGetScanFilterManufacturerDataMask( 583 @RpcParameter(name = "index") 584 Integer index, 585 @RpcParameter(name = "filterIndex") 586 Integer filterIndex) 587 throws Exception { 588 if (mScanFilterList.get(index) != null) { 589 if (mScanFilterList.get(index).get(filterIndex) != null) { 590 return mScanFilterList.get(index).get( 591 filterIndex).getManufacturerDataMask(); 592 } else { 593 throw new Exception("Invalid filterIndex input:" 594 + Integer.toString(filterIndex)); 595 } 596 } else { 597 throw new Exception("Invalid index input:" 598 + Integer.toString(index)); 599 } 600 } 601 602 /** 603 * Get ScanFilter's service data 604 * 605 * @param index the ScanFilter object to use 606 * @return the ScanFilter's service data 607 * @throws Exception 608 */ 609 @Rpc(description = "Get ScanFilter's service data") 610 public byte[] bleGetScanFilterServiceData( 611 @RpcParameter(name = "index") 612 Integer index, 613 @RpcParameter(name = "filterIndex") 614 Integer filterIndex) 615 throws Exception { 616 if (mScanFilterList.get(index) != null) { 617 if (mScanFilterList.get(index).get(filterIndex) != null) { 618 return mScanFilterList.get(index).get( 619 filterIndex).getServiceData(); 620 } else { 621 throw new Exception("Invalid filterIndex input:" 622 + Integer.toString(filterIndex)); 623 } 624 } else { 625 throw new Exception("Invalid index input:" 626 + Integer.toString(index)); 627 } 628 } 629 630 /** 631 * Get ScanFilter's service data mask 632 * 633 * @param index the ScanFilter object to use 634 * @return the ScanFilter's service data mask 635 * @throws Exception 636 */ 637 @Rpc(description = "Get ScanFilter's service data mask") 638 public byte[] bleGetScanFilterServiceDataMask( 639 @RpcParameter(name = "index") 640 Integer index, 641 @RpcParameter(name = "filterIndex") 642 Integer filterIndex) 643 throws Exception { 644 if (mScanFilterList.get(index) != null) { 645 if (mScanFilterList.get(index).get(filterIndex) != null) { 646 return mScanFilterList.get(index).get( 647 filterIndex).getServiceDataMask(); 648 } else { 649 throw new Exception("Invalid filterIndex input:" 650 + Integer.toString(filterIndex)); 651 } 652 } else { 653 throw new Exception("Invalid index input:" 654 + Integer.toString(index)); 655 } 656 } 657 658 /** 659 * Get ScanFilter's service uuid 660 * 661 * @param index the ScanFilter object to use 662 * @return the ScanFilter's service uuid 663 * @throws Exception 664 */ 665 @Rpc(description = "Get ScanFilter's service uuid") 666 public String bleGetScanFilterServiceUuid( 667 @RpcParameter(name = "index") 668 Integer index, 669 @RpcParameter(name = "filterIndex") 670 Integer filterIndex) 671 throws Exception { 672 if (mScanFilterList.get(index) != null) { 673 if (mScanFilterList.get(index).get(filterIndex) != null) { 674 if (mScanFilterList.get(index).get( 675 filterIndex).getServiceUuid() != null) { 676 return mScanFilterList.get(index).get( 677 filterIndex).getServiceUuid().toString(); 678 } else { 679 throw new Exception("No Service Uuid set for filter:" 680 + Integer.toString(filterIndex)); 681 } 682 } else { 683 throw new Exception("Invalid filterIndex input:" 684 + Integer.toString(filterIndex)); 685 } 686 } else { 687 throw new Exception("Invalid index input:" 688 + Integer.toString(index)); 689 } 690 } 691 692 /** 693 * Get ScanFilter's service uuid mask 694 * 695 * @param index the ScanFilter object to use 696 * @return the ScanFilter's service uuid mask 697 * @throws Exception 698 */ 699 @Rpc(description = "Get ScanFilter's service uuid mask") 700 public String bleGetScanFilterServiceUuidMask( 701 @RpcParameter(name = "index") 702 Integer index, 703 @RpcParameter(name = "filterIndex") 704 Integer filterIndex) 705 throws Exception { 706 if (mScanFilterList.get(index) != null) { 707 if (mScanFilterList.get(index).get(filterIndex) != null) { 708 if (mScanFilterList.get(index).get( 709 filterIndex).getServiceUuidMask() != null) { 710 return mScanFilterList.get( 711 index).get(filterIndex).getServiceUuidMask() 712 .toString(); 713 } else { 714 throw new Exception("No Service Uuid Mask set for filter:" 715 + Integer.toString(filterIndex)); 716 } 717 } else { 718 throw new Exception("Invalid filterIndex input:" 719 + Integer.toString(filterIndex)); 720 } 721 } else { 722 throw new Exception("Invalid index input:" 723 + Integer.toString(index)); 724 } 725 } 726 727 /** 728 * Add filter "macAddress" to existing ScanFilter 729 * 730 * @param macAddress the macAddress to filter against 731 * @throws Exception 732 */ 733 @Rpc(description = "Add filter \"macAddress\" to existing ScanFilter") 734 public void bleSetScanFilterDeviceAddress( 735 @RpcParameter(name = "macAddress") 736 String macAddress 737 ) { 738 mScanFilterBuilder.setDeviceAddress(macAddress); 739 } 740 741 /** 742 * Add filter "manufacturereDataId and/or manufacturerData" to existing 743 * ScanFilter 744 * @param manufacturerDataId the manufacturer data id to filter against 745 * @param manufacturerDataMask the manufacturere data mask to filter against 746 * @throws Exception 747 */ 748 @Rpc(description = "Add filter \"manufacturereDataId and/or manufacturerData\" to existing ScanFilter") 749 public void bleSetScanFilterManufacturerData( 750 @RpcParameter(name = "manufacturerDataId") 751 Integer manufacturerDataId, 752 @RpcParameter(name = "manufacturerData") 753 byte[] manufacturerData, 754 @RpcParameter(name = "manufacturerDataMask") 755 @RpcOptional 756 byte[] manufacturerDataMask 757 ){ 758 if (manufacturerDataMask != null) { 759 mScanFilterBuilder.setManufacturerData(manufacturerDataId, 760 manufacturerData, manufacturerDataMask); 761 } else { 762 mScanFilterBuilder.setManufacturerData(manufacturerDataId, 763 manufacturerData); 764 } 765 } 766 767 /** 768 * Add filter "serviceData and serviceDataMask" to existing ScanFilter 769 * 770 * @param serviceData the service data to filter against 771 * @param serviceDataMask the servie data mask to filter against 772 * @throws Exception 773 */ 774 @Rpc(description = "Add filter \"serviceData and serviceDataMask\" to existing ScanFilter ") 775 public void bleSetScanFilterServiceData( 776 @RpcParameter(name = "serviceUuid") String serviceUuid, 777 @RpcParameter(name = "serviceData") byte[] serviceData, 778 @RpcParameter(name = "serviceDataMask") 779 @RpcOptional byte[] serviceDataMask 780 ) { 781 if (serviceDataMask != null) { 782 mScanFilterBuilder 783 .setServiceData( 784 ParcelUuid.fromString(serviceUuid), 785 serviceData, serviceDataMask); 786 } else { 787 mScanFilterBuilder.setServiceData(ParcelUuid.fromString(serviceUuid), 788 serviceData); 789 } 790 } 791 792 /** 793 * Add filter "serviceUuid and/or serviceMask" to existing ScanFilter 794 * 795 * @param serviceUuid the service uuid to filter against 796 * @param serviceMask the service mask to filter against 797 * @throws Exception 798 */ 799 @Rpc(description = "Add filter \"serviceUuid and/or serviceMask\" to existing ScanFilter") 800 public void bleSetScanFilterServiceUuid( 801 @RpcParameter(name = "serviceUuid") 802 String serviceUuid, 803 @RpcParameter(name = "serviceMask") 804 @RpcOptional 805 String serviceMask 806 ) { 807 if (serviceMask != null) { 808 mScanFilterBuilder 809 .setServiceUuid(ParcelUuid.fromString(serviceUuid), 810 ParcelUuid.fromString(serviceMask)); 811 } else { 812 mScanFilterBuilder.setServiceUuid(ParcelUuid.fromString(serviceUuid)); 813 } 814 } 815 816 /** 817 * Add filter "device name" to existing ScanFilter 818 * 819 * @param name the device name to filter against 820 * @throws Exception 821 */ 822 @Rpc(description = "Sets the scan filter's device name") 823 public void bleSetScanFilterDeviceName( 824 @RpcParameter(name = "name") 825 String name 826 ) { 827 mScanFilterBuilder.setDeviceName(name); 828 } 829 830 @Rpc(description = "Set the scan setting's match mode") 831 public void bleSetScanSettingsMatchMode( 832 @RpcParameter(name = "mode") Integer mode) { 833 mScanSettingsBuilder.setMatchMode(mode); 834 } 835 836 @Rpc(description = "Get the scan setting's match mode") 837 public int bleGetScanSettingsMatchMode( 838 @RpcParameter(name = "scanSettingsIndex") Integer scanSettingsIndex 839 ) { 840 return mScanSettingsList.get(scanSettingsIndex).getMatchMode(); 841 } 842 843 @Rpc(description = "Set the scan setting's number of matches") 844 public void bleSetScanSettingsNumOfMatches( 845 @RpcParameter(name = "matches") Integer matches) { 846 mScanSettingsBuilder.setNumOfMatches(matches); 847 } 848 849 @Rpc(description = "Get the scan setting's number of matches") 850 public int bleGetScanSettingsNumberOfMatches( 851 @RpcParameter(name = "scanSettingsIndex") 852 Integer scanSettingsIndex) { 853 return mScanSettingsList.get(scanSettingsIndex).getNumOfMatches(); 854 } 855 856 private class myScanCallback extends ScanCallback { 857 public Integer index; 858 String mEventType; 859 private final Bundle mResults; 860 861 public myScanCallback(Integer idx) { 862 index = idx; 863 mEventType = "BleScan"; 864 mResults = new Bundle(); 865 } 866 867 @Override 868 public void onScanFailed(int errorCode) { 869 String errorString = "UNKNOWN_ERROR_CODE"; 870 if (errorCode == ScanCallback.SCAN_FAILED_ALREADY_STARTED) { 871 errorString = "SCAN_FAILED_ALREADY_STARTED"; 872 } else if (errorCode 873 == ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED) { 874 errorString = "SCAN_FAILED_APPLICATION_REGISTRATION_FAILED"; 875 } else if (errorCode 876 == ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED) { 877 errorString = "SCAN_FAILED_FEATURE_UNSUPPORTED"; 878 } else if (errorCode == ScanCallback.SCAN_FAILED_INTERNAL_ERROR) { 879 errorString = "SCAN_FAILED_INTERNAL_ERROR"; 880 } 881 Log.d("bluetooth_le_scan change onScanFailed " 882 + mEventType + " " + index + " error " 883 + errorString); 884 mResults.putInt("ID", index); 885 mResults.putString("Type", "onScanFailed"); 886 mResults.putInt("ErrorCode", errorCode); 887 mResults.putString("Error", errorString); 888 mEventFacade.postEvent(mEventType + index + "onScanFailed", 889 mResults.clone()); 890 mResults.clear(); 891 } 892 893 @Override 894 public void onScanResult(int callbackType, ScanResult result) { 895 Log.d("bluetooth_le_scan change onUpdate " 896 + mEventType + " " + index); 897 mResults.putInt("ID", index); 898 mResults.putInt("CallbackType", callbackType); 899 mResults.putString("Type", "onScanResult"); 900 mResults.putParcelable("Result", result); 901 mEventFacade.postEvent( 902 mEventType + index + "onScanResults", mResults.clone()); 903 mResults.clear(); 904 } 905 906 @Override 907 public void onBatchScanResults(List<ScanResult> results) { 908 Log.d("reportResult " + mEventType + " " + index); 909 mResults.putLong("Timestamp", System.currentTimeMillis() / 1000); 910 mResults.putInt("ID", index); 911 mResults.putString("Type", "onBatchScanResults"); 912 mResults.putParcelableList("Results", results); 913 mEventFacade.postEvent(mEventType 914 + index + "onBatchScanResult", mResults.clone()); 915 mResults.clear(); 916 } 917 } 918 919 private class myLeScanCallback implements LeScanCallback { 920 public Integer index; 921 String mEventType; 922 private final Bundle mResults; 923 924 public myLeScanCallback(Integer idx) { 925 index = idx; 926 mEventType = "ClassicBleScan"; 927 mResults = new Bundle(); 928 } 929 930 @Override 931 public void onLeScan( 932 BluetoothDevice device, int rssi, byte[] scanRecord) { 933 Log.d("bluetooth_classic_le_scan " + mEventType + " " + index); 934 mResults.putParcelable("Device", device); 935 mResults.putInt("Rssi", rssi); 936 mResults.putByteArray("ScanRecord", scanRecord); 937 mResults.putString("Type", "onLeScan"); 938 mEventFacade.postEvent(mEventType 939 + index + "onLeScan", mResults.clone()); 940 mResults.clear(); 941 } 942 } 943 944 @Override 945 public void shutdown() { 946 if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) { 947 for (myScanCallback mScanCallback : mScanCallbackList.values()) { 948 if (mScanCallback != null) { 949 try { 950 mBluetoothAdapter.getBluetoothLeScanner() 951 .stopScan(mScanCallback); 952 } catch (NullPointerException e) { 953 Log.e("Failed to stop ble scan callback.", e); 954 } 955 } 956 } 957 for (myLeScanCallback mLeScanCallback : mLeScanCallbackList.values()) { 958 if (mLeScanCallback != null) { 959 try { 960 mBluetoothAdapter.stopLeScan(mLeScanCallback); 961 } catch (NullPointerException e) { 962 Log.e("Failed to stop classic ble scan callback.", e); 963 } 964 } 965 } 966 } 967 mScanCallbackList.clear(); 968 mScanFilterList.clear(); 969 mScanSettingsList.clear(); 970 mLeScanCallbackList.clear(); 971 } 972 } 973