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