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.le.BluetoothLeScanner; 29 import android.bluetooth.le.ScanCallback; 30 import android.bluetooth.le.ScanFilter; 31 import android.bluetooth.BluetoothAdapter.LeScanCallback; 32 import android.bluetooth.le.ScanFilter.Builder; 33 import android.bluetooth.le.ScanResult; 34 import android.bluetooth.le.ScanSettings; 35 import android.os.Bundle; 36 import android.os.ParcelUuid; 37 38 import com.googlecode.android_scripting.Log; 39 import com.googlecode.android_scripting.MainThread; 40 import com.googlecode.android_scripting.facade.EventFacade; 41 import com.googlecode.android_scripting.facade.FacadeManager; 42 import com.googlecode.android_scripting.jsonrpc.RpcReceiver; 43 import com.googlecode.android_scripting.rpc.Rpc; 44 import com.googlecode.android_scripting.rpc.RpcOptional; 45 import com.googlecode.android_scripting.rpc.RpcParameter; 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 BluetoothLeScanFacade(FacadeManager manager)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") bleGenScanCallback()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") bleGenLeScanCallback()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") bleGenFilterList()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") bleBuildScanFilter( @pcParametername = "filterIndex") Integer filterIndex )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") bleBuildScanSetting()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") bleStopBleScan( @pcParametername = "index") Integer index)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") bleStopClassicBleScan( @pcParametername = "index") Integer index)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") bleStartBleScan( @pcParametername = "filterListIndex") Integer filterListIndex, @RpcParameter(name = "scanSettingsIndex") Integer scanSettingsIndex, @RpcParameter(name = "callbackIndex") Integer callbackIndex )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, mScanCallbackList.get(callbackIndex)); 230 } else { 231 throw new Exception("Invalid filterListIndex input:" 232 + Integer.toString(filterListIndex)); 233 } 234 } 235 236 /** 237 * Starts a classic ble scan 238 * 239 * @param index the id of the myScan whose ScanCallback to start 240 * @throws Exception 241 */ 242 @Rpc(description = "Starts a classic ble advertisement scan") bleStartClassicBleScan( @pcParametername = "leCallbackIndex") Integer leCallbackIndex )243 public boolean bleStartClassicBleScan( 244 @RpcParameter(name = "leCallbackIndex") 245 Integer leCallbackIndex 246 ) throws Exception { 247 Log.d("bluetooth_le_scan starting a background scan"); 248 boolean result = false; 249 if (mLeScanCallbackList.get(leCallbackIndex) != null) { 250 result = mBluetoothAdapter.startLeScan(mLeScanCallbackList.get(leCallbackIndex)); 251 } else { 252 throw new Exception("Invalid leCallbackIndex input:" 253 + Integer.toString(leCallbackIndex)); 254 } 255 return result; 256 } 257 258 /** 259 * Starts a classic ble scan with service Uuids 260 * 261 * @param index the id of the myScan whose ScanCallback to start 262 * @throws Exception 263 */ 264 @Rpc(description = "Starts a classic ble advertisement scan with service Uuids") bleStartClassicBleScanWithServiceUuids( @pcParametername = "leCallbackIndex") Integer leCallbackIndex, @RpcParameter(name = "serviceUuids") String[] serviceUuidList )265 public boolean bleStartClassicBleScanWithServiceUuids( 266 @RpcParameter(name = "leCallbackIndex") 267 Integer leCallbackIndex, 268 @RpcParameter(name = "serviceUuids") 269 String[] serviceUuidList 270 ) throws Exception { 271 Log.d("bluetooth_le_scan starting a background scan"); 272 UUID[] serviceUuids = new UUID[serviceUuidList.length]; 273 for (int i = 0; i < serviceUuidList.length; i++) { 274 serviceUuids[i] = UUID.fromString(serviceUuidList[i]); 275 } 276 boolean result = false; 277 if (mLeScanCallbackList.get(leCallbackIndex) != null) { 278 result = mBluetoothAdapter.startLeScan(serviceUuids, 279 mLeScanCallbackList.get(leCallbackIndex)); 280 } else { 281 throw new Exception("Invalid leCallbackIndex input:" 282 + Integer.toString(leCallbackIndex)); 283 } 284 return result; 285 } 286 287 /** 288 * Trigger onBatchScanResults 289 * 290 * @throws Exception 291 */ 292 @Rpc(description = "Gets the results of the ble ScanCallback") bleFlushPendingScanResults( @pcParametername = "callbackIndex") Integer callbackIndex )293 public void bleFlushPendingScanResults( 294 @RpcParameter(name = "callbackIndex") 295 Integer callbackIndex 296 ) throws Exception { 297 if (mScanCallbackList.get(callbackIndex) != null) { 298 mBluetoothAdapter 299 .getBluetoothLeScanner().flushPendingScanResults( 300 mScanCallbackList.get(callbackIndex)); 301 } else { 302 throw new Exception("Invalid callbackIndex input:" 303 + Integer.toString(callbackIndex)); 304 } 305 } 306 307 /** 308 * Set scanSettings for ble scan. Note: You have to set all variables at once. 309 * 310 * @param callbackType Bluetooth LE scan callback type 311 * @param reportDelaySeconds Time of delay for reporting the scan result 312 * @param scanMode Bluetooth LE scan mode. 313 * @param scanResultType Bluetooth LE scan result type 314 * @throws Exception 315 */ 316 317 /** 318 * Set the scan setting's callback type 319 * @param callbackType Bluetooth LE scan callback type 320 */ 321 @Rpc(description = "Set the scan setting's callback type") bleSetScanSettingsCallbackType( @pcParametername = "callbackType") Integer callbackType)322 public void bleSetScanSettingsCallbackType( 323 @RpcParameter(name = "callbackType") 324 Integer callbackType) { 325 mScanSettingsBuilder.setCallbackType(callbackType); 326 } 327 328 /** 329 * Set the scan setting's report delay millis 330 * @param reportDelayMillis Time of delay for reporting the scan result 331 */ 332 @Rpc(description = "Set the scan setting's report delay millis") bleSetScanSettingsReportDelayMillis( @pcParametername = "reportDelayMillis") Long reportDelayMillis)333 public void bleSetScanSettingsReportDelayMillis( 334 @RpcParameter(name = "reportDelayMillis") 335 Long reportDelayMillis) { 336 mScanSettingsBuilder.setReportDelay(reportDelayMillis); 337 } 338 339 /** 340 * Set the scan setting's scan mode 341 * @param scanMode Bluetooth LE scan mode. 342 */ 343 @Rpc(description = "Set the scan setting's scan mode") bleSetScanSettingsScanMode( @pcParametername = "scanMode") Integer scanMode)344 public void bleSetScanSettingsScanMode( 345 @RpcParameter(name = "scanMode") 346 Integer scanMode) { 347 mScanSettingsBuilder.setScanMode(scanMode); 348 } 349 350 /** 351 * Set the scan setting's scan result type 352 * @param scanResultType Bluetooth LE scan result type 353 */ 354 @Rpc(description = "Set the scan setting's scan result type") bleSetScanSettingsResultType( @pcParametername = "scanResultType") Integer scanResultType)355 public void bleSetScanSettingsResultType( 356 @RpcParameter(name = "scanResultType") 357 Integer scanResultType) { 358 mScanSettingsBuilder.setScanResultType(scanResultType); 359 } 360 /** 361 * Get ScanSetting's callback type 362 * 363 * @param index the ScanSetting object to use 364 * @return the ScanSetting's callback type 365 * @throws Exception 366 */ 367 @Rpc(description = "Get ScanSetting's callback type") bleGetScanSettingsCallbackType( @pcParametername = "index") Integer index )368 public Integer bleGetScanSettingsCallbackType( 369 @RpcParameter(name = "index") 370 Integer index 371 ) throws Exception { 372 if (mScanSettingsList.get(index) != null) { 373 ScanSettings mScanSettings = mScanSettingsList.get(index); 374 return mScanSettings.getCallbackType(); 375 } else { 376 throw new Exception("Invalid index input:" + Integer.toString(index)); 377 } 378 } 379 380 /** 381 * Get ScanSetting's report delay in milli seconds 382 * 383 * @param index the ScanSetting object to useSystemClock 384 * @return the ScanSetting's report delay in milliseconds 385 * @throws Exception 386 */ 387 @Rpc(description = "Get ScanSetting's report delay milliseconds") bleGetScanSettingsReportDelayMillis( @pcParametername = "index") Integer index)388 public Long bleGetScanSettingsReportDelayMillis( 389 @RpcParameter(name = "index") 390 Integer index) throws Exception { 391 if (mScanSettingsList.get(index) != null) { 392 ScanSettings mScanSettings = mScanSettingsList.get(index); 393 return mScanSettings.getReportDelayMillis(); 394 } else { 395 throw new Exception("Invalid index input:" + Integer.toString(index)); 396 } 397 } 398 399 /** 400 * Get ScanSetting's scan mode 401 * 402 * @param index the ScanSetting object to use 403 * @return the ScanSetting's scan mode 404 * @throws Exception 405 */ 406 @Rpc(description = "Get ScanSetting's scan mode") bleGetScanSettingsScanMode( @pcParametername = "index") Integer index)407 public Integer bleGetScanSettingsScanMode( 408 @RpcParameter(name = "index") 409 Integer index) throws Exception { 410 if (mScanSettingsList.get(index) != null) { 411 ScanSettings mScanSettings = mScanSettingsList.get(index); 412 return mScanSettings.getScanMode(); 413 } else { 414 throw new Exception("Invalid index input:" + Integer.toString(index)); 415 } 416 } 417 418 /** 419 * Get ScanSetting's scan result type 420 * 421 * @param index the ScanSetting object to use 422 * @return the ScanSetting's scan result type 423 * @throws Exception 424 */ 425 @Rpc(description = "Get ScanSetting's scan result type") bleGetScanSettingsScanResultType( @pcParametername = "index") Integer index)426 public Integer bleGetScanSettingsScanResultType( 427 @RpcParameter(name = "index") 428 Integer index) throws Exception { 429 if (mScanSettingsList.get(index) != null) { 430 ScanSettings mScanSettings = mScanSettingsList.get(index); 431 return mScanSettings.getScanResultType(); 432 } else { 433 throw new Exception("Invalid index input:" + Integer.toString(index)); 434 } 435 } 436 437 /** 438 * Get ScanFilter's Manufacturer Id 439 * 440 * @param index the ScanFilter object to use 441 * @return the ScanFilter's manufacturer id 442 * @throws Exception 443 */ 444 @Rpc(description = "Get ScanFilter's Manufacturer Id") bleGetScanFilterManufacturerId( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)445 public Integer bleGetScanFilterManufacturerId( 446 @RpcParameter(name = "index") 447 Integer index, 448 @RpcParameter(name = "filterIndex") 449 Integer filterIndex) 450 throws Exception { 451 if (mScanFilterList.get(index) != null) { 452 if (mScanFilterList.get(index).get(filterIndex) != null) { 453 return mScanFilterList.get(index) 454 .get(filterIndex).getManufacturerId(); 455 } else { 456 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 457 } 458 } else { 459 throw new Exception("Invalid index input:" + Integer.toString(index)); 460 } 461 } 462 463 /** 464 * Get ScanFilter's device address 465 * 466 * @param index the ScanFilter object to use 467 * @return the ScanFilter's device address 468 * @throws Exception 469 */ 470 @Rpc(description = "Get ScanFilter's device address") bleGetScanFilterDeviceAddress( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)471 public String bleGetScanFilterDeviceAddress( 472 @RpcParameter(name = "index") 473 Integer index, 474 @RpcParameter(name = "filterIndex") 475 Integer filterIndex) 476 throws Exception { 477 if (mScanFilterList.get(index) != null) { 478 if (mScanFilterList.get(index).get(filterIndex) != null) { 479 return mScanFilterList.get(index).get(filterIndex).getDeviceAddress(); 480 } else { 481 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 482 } 483 } else { 484 throw new Exception("Invalid index input:" + Integer.toString(index)); 485 } 486 } 487 488 /** 489 * Get ScanFilter's device name 490 * 491 * @param index the ScanFilter object to use 492 * @return the ScanFilter's device name 493 * @throws Exception 494 */ 495 @Rpc(description = "Get ScanFilter's device name") bleGetScanFilterDeviceName( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)496 public String bleGetScanFilterDeviceName( 497 @RpcParameter(name = "index") 498 Integer index, 499 @RpcParameter(name = "filterIndex") 500 Integer filterIndex) 501 throws Exception { 502 if (mScanFilterList.get(index) != null) { 503 if (mScanFilterList.get(index).get(filterIndex) != null) { 504 return mScanFilterList.get(index).get(filterIndex).getDeviceName(); 505 } else { 506 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 507 } 508 } else { 509 throw new Exception("Invalid index input:" + Integer.toString(index)); 510 } 511 } 512 513 /** 514 * Get ScanFilter's manufacturer data 515 * 516 * @param index the ScanFilter object to use 517 * @return the ScanFilter's manufacturer data 518 * @throws Exception 519 */ 520 @Rpc(description = "Get ScanFilter's manufacturer data") bleGetScanFilterManufacturerData( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)521 public byte[] bleGetScanFilterManufacturerData( 522 @RpcParameter(name = "index") 523 Integer index, 524 @RpcParameter(name = "filterIndex") 525 Integer filterIndex) 526 throws Exception { 527 if (mScanFilterList.get(index) != null) { 528 if (mScanFilterList.get(index).get(filterIndex) != null) { 529 return mScanFilterList.get(index).get(filterIndex).getManufacturerData(); 530 } else { 531 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 532 } 533 } else { 534 throw new Exception("Invalid index input:" + Integer.toString(index)); 535 } 536 } 537 538 /** 539 * Get ScanFilter's manufacturer data mask 540 * 541 * @param index the ScanFilter object to use 542 * @return the ScanFilter's manufacturer data mask 543 * @throws Exception 544 */ 545 @Rpc(description = "Get ScanFilter's manufacturer data mask") bleGetScanFilterManufacturerDataMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)546 public byte[] bleGetScanFilterManufacturerDataMask( 547 @RpcParameter(name = "index") 548 Integer index, 549 @RpcParameter(name = "filterIndex") 550 Integer filterIndex) 551 throws Exception { 552 if (mScanFilterList.get(index) != null) { 553 if (mScanFilterList.get(index).get(filterIndex) != null) { 554 return mScanFilterList.get(index).get(filterIndex).getManufacturerDataMask(); 555 } else { 556 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 557 } 558 } else { 559 throw new Exception("Invalid index input:" + Integer.toString(index)); 560 } 561 } 562 563 /** 564 * Get ScanFilter's service data 565 * 566 * @param index the ScanFilter object to use 567 * @return the ScanFilter's service data 568 * @throws Exception 569 */ 570 @Rpc(description = "Get ScanFilter's service data") bleGetScanFilterServiceData( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)571 public byte[] bleGetScanFilterServiceData( 572 @RpcParameter(name = "index") 573 Integer index, 574 @RpcParameter(name = "filterIndex") 575 Integer filterIndex) 576 throws Exception { 577 if (mScanFilterList.get(index) != null) { 578 if (mScanFilterList.get(index).get(filterIndex) != null) { 579 return mScanFilterList.get(index).get(filterIndex).getServiceData(); 580 } else { 581 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 582 } 583 } else { 584 throw new Exception("Invalid index input:" + Integer.toString(index)); 585 } 586 } 587 588 /** 589 * Get ScanFilter's service data mask 590 * 591 * @param index the ScanFilter object to use 592 * @return the ScanFilter's service data mask 593 * @throws Exception 594 */ 595 @Rpc(description = "Get ScanFilter's service data mask") bleGetScanFilterServiceDataMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)596 public byte[] bleGetScanFilterServiceDataMask( 597 @RpcParameter(name = "index") 598 Integer index, 599 @RpcParameter(name = "filterIndex") 600 Integer filterIndex) 601 throws Exception { 602 if (mScanFilterList.get(index) != null) { 603 if (mScanFilterList.get(index).get(filterIndex) != null) { 604 return mScanFilterList.get(index).get(filterIndex).getServiceDataMask(); 605 } else { 606 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 607 } 608 } else { 609 throw new Exception("Invalid index input:" + Integer.toString(index)); 610 } 611 } 612 613 /** 614 * Get ScanFilter's service uuid 615 * 616 * @param index the ScanFilter object to use 617 * @return the ScanFilter's service uuid 618 * @throws Exception 619 */ 620 @Rpc(description = "Get ScanFilter's service uuid") bleGetScanFilterServiceUuid( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)621 public String bleGetScanFilterServiceUuid( 622 @RpcParameter(name = "index") 623 Integer index, 624 @RpcParameter(name = "filterIndex") 625 Integer filterIndex) 626 throws Exception { 627 if (mScanFilterList.get(index) != null) { 628 if (mScanFilterList.get(index).get(filterIndex) != null) { 629 if (mScanFilterList.get(index).get(filterIndex).getServiceUuid() != null) { 630 return mScanFilterList.get(index).get(filterIndex).getServiceUuid().toString(); 631 } else { 632 throw new Exception("No Service Uuid set for filter:" 633 + Integer.toString(filterIndex)); 634 } 635 } else { 636 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 637 } 638 } else { 639 throw new Exception("Invalid index input:" + Integer.toString(index)); 640 } 641 } 642 643 /** 644 * Get ScanFilter's service uuid mask 645 * 646 * @param index the ScanFilter object to use 647 * @return the ScanFilter's service uuid mask 648 * @throws Exception 649 */ 650 @Rpc(description = "Get ScanFilter's service uuid mask") bleGetScanFilterServiceUuidMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)651 public String bleGetScanFilterServiceUuidMask( 652 @RpcParameter(name = "index") 653 Integer index, 654 @RpcParameter(name = "filterIndex") 655 Integer filterIndex) 656 throws Exception { 657 if (mScanFilterList.get(index) != null) { 658 if (mScanFilterList.get(index).get(filterIndex) != null) { 659 if (mScanFilterList.get(index).get(filterIndex).getServiceUuidMask() != null) { 660 return mScanFilterList.get(index).get(filterIndex).getServiceUuidMask() 661 .toString(); 662 } else { 663 throw new Exception("No Service Uuid Mask set for filter:" 664 + Integer.toString(filterIndex)); 665 } 666 } else { 667 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex)); 668 } 669 } else { 670 throw new Exception("Invalid index input:" + Integer.toString(index)); 671 } 672 } 673 674 /** 675 * Add filter "macAddress" to existing ScanFilter 676 * 677 * @param macAddress the macAddress to filter against 678 * @throws Exception 679 */ 680 @Rpc(description = "Add filter \"macAddress\" to existing ScanFilter") bleSetScanFilterDeviceAddress( @pcParametername = "macAddress") String macAddress )681 public void bleSetScanFilterDeviceAddress( 682 @RpcParameter(name = "macAddress") 683 String macAddress 684 ) { 685 mScanFilterBuilder.setDeviceAddress(macAddress); 686 } 687 688 /** 689 * Add filter "manufacturereDataId and/or manufacturerData" to existing ScanFilter 690 * 691 * @param manufacturerDataId the manufacturer data id to filter against 692 * @param manufacturerDataMask the manufacturere data mask to filter against 693 * @throws Exception 694 */ 695 @Rpc(description = "Add filter \"manufacturereDataId and/or manufacturerData\" to existing ScanFilter") bleSetScanFilterManufacturerData( @pcParametername = "manufacturerDataId") Integer manufacturerDataId, @RpcParameter(name = "manufacturerData") byte[] manufacturerData, @RpcParameter(name = "manufacturerDataMask") @RpcOptional byte[] manufacturerDataMask )696 public void bleSetScanFilterManufacturerData( 697 @RpcParameter(name = "manufacturerDataId") 698 Integer manufacturerDataId, 699 @RpcParameter(name = "manufacturerData") 700 byte[] manufacturerData, 701 @RpcParameter(name = "manufacturerDataMask") 702 @RpcOptional 703 byte[] manufacturerDataMask 704 ){ 705 if (manufacturerDataMask != null) { 706 mScanFilterBuilder.setManufacturerData(manufacturerDataId, 707 manufacturerData, manufacturerDataMask); 708 } else { 709 mScanFilterBuilder.setManufacturerData(manufacturerDataId, 710 manufacturerData); 711 } 712 } 713 714 /** 715 * Add filter "serviceData and serviceDataMask" to existing ScanFilter 716 * 717 * @param serviceData the service data to filter against 718 * @param serviceDataMask the servie data mask to filter against 719 * @throws Exception 720 */ 721 @Rpc(description = "Add filter \"serviceData and serviceDataMask\" to existing ScanFilter ") bleSetScanFilterServiceData( @pcParametername = "serviceUuid") String serviceUuid, @RpcParameter(name = "serviceData") byte[] serviceData, @RpcParameter(name = "serviceDataMask") @RpcOptional byte[] serviceDataMask )722 public void bleSetScanFilterServiceData( 723 @RpcParameter(name = "serviceUuid") 724 String serviceUuid, 725 @RpcParameter(name = "serviceData") 726 byte[] serviceData, 727 @RpcParameter(name = "serviceDataMask") 728 @RpcOptional 729 byte[] serviceDataMask 730 ) { 731 if (serviceDataMask != null) { 732 mScanFilterBuilder 733 .setServiceData( 734 ParcelUuid.fromString(serviceUuid), 735 serviceData, serviceDataMask); 736 } else { 737 mScanFilterBuilder.setServiceData(ParcelUuid.fromString(serviceUuid), 738 serviceData); 739 } 740 } 741 742 /** 743 * Add filter "serviceUuid and/or serviceMask" to existing ScanFilter 744 * 745 * @param serviceUuid the service uuid to filter against 746 * @param serviceMask the service mask to filter against 747 * @throws Exception 748 */ 749 @Rpc(description = "Add filter \"serviceUuid and/or serviceMask\" to existing ScanFilter") bleSetScanFilterServiceUuid( @pcParametername = "serviceUuid") String serviceUuid, @RpcParameter(name = "serviceMask") @RpcOptional String serviceMask )750 public void bleSetScanFilterServiceUuid( 751 @RpcParameter(name = "serviceUuid") 752 String serviceUuid, 753 @RpcParameter(name = "serviceMask") 754 @RpcOptional 755 String serviceMask 756 ) { 757 if (serviceMask != null) { 758 mScanFilterBuilder 759 .setServiceUuid(ParcelUuid.fromString(serviceUuid), 760 ParcelUuid.fromString(serviceMask)); 761 } else { 762 mScanFilterBuilder.setServiceUuid(ParcelUuid.fromString(serviceUuid)); 763 } 764 } 765 766 /** 767 * Add filter "device name" to existing ScanFilter 768 * 769 * @param name the device name to filter against 770 * @throws Exception 771 */ 772 @Rpc(description = "Sets the scan filter's device name") bleSetScanFilterDeviceName( @pcParametername = "name") String name )773 public void bleSetScanFilterDeviceName( 774 @RpcParameter(name = "name") 775 String name 776 ) { 777 mScanFilterBuilder.setDeviceName(name); 778 } 779 780 @Rpc(description = "Set the scan setting's match mode") bleSetScanSettingsMatchMode( @pcParametername = "mode") Integer mode)781 public void bleSetScanSettingsMatchMode( 782 @RpcParameter(name = "mode") Integer mode) { 783 mScanSettingsBuilder.setMatchMode(mode); 784 } 785 786 @Rpc(description = "Get the scan setting's match mode") bleGetScanSettingsMatchMode( @pcParametername = "scanSettingsIndex") Integer scanSettingsIndex )787 public int bleGetScanSettingsMatchMode( 788 @RpcParameter(name = "scanSettingsIndex") Integer scanSettingsIndex 789 ) { 790 return mScanSettingsList.get(scanSettingsIndex).getMatchMode(); 791 } 792 793 @Rpc(description = "Set the scan setting's number of matches") bleSetScanSettingsNumOfMatches( @pcParametername = "matches") Integer matches)794 public void bleSetScanSettingsNumOfMatches( 795 @RpcParameter(name = "matches") Integer matches) { 796 mScanSettingsBuilder.setNumOfMatches(matches); 797 } 798 799 @Rpc(description = "Get the scan setting's number of matches") bleGetScanSettingsNumberOfMatches( @pcParametername = "scanSettingsIndex") Integer scanSettingsIndex)800 public int bleGetScanSettingsNumberOfMatches( 801 @RpcParameter(name = "scanSettingsIndex") 802 Integer scanSettingsIndex) { 803 return mScanSettingsList.get(scanSettingsIndex).getNumOfMatches(); 804 } 805 806 private class myScanCallback extends ScanCallback { 807 public Integer index; 808 String mEventType; 809 private final Bundle mResults; 810 myScanCallback(Integer idx)811 public myScanCallback(Integer idx) { 812 index = idx; 813 mEventType = "BleScan"; 814 mResults = new Bundle(); 815 } 816 817 @Override onScanFailed(int errorCode)818 public void onScanFailed(int errorCode) { 819 String errorString = "UNKNOWN_ERROR_CODE"; 820 if (errorCode == ScanCallback.SCAN_FAILED_ALREADY_STARTED) { 821 errorString = "SCAN_FAILED_ALREADY_STARTED"; 822 } else if (errorCode == ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED) { 823 errorString = "SCAN_FAILED_APPLICATION_REGISTRATION_FAILED"; 824 } else if (errorCode == ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED) { 825 errorString = "SCAN_FAILED_FEATURE_UNSUPPORTED"; 826 } else if (errorCode == ScanCallback.SCAN_FAILED_INTERNAL_ERROR) { 827 errorString = "SCAN_FAILED_INTERNAL_ERROR"; 828 } 829 Log.d("bluetooth_le_scan change onScanFailed " + mEventType + " " + index + " error " 830 + errorString); 831 mResults.putInt("ID", index); 832 mResults.putString("Type", "onScanFailed"); 833 mResults.putInt("ErrorCode", errorCode); 834 mResults.putString("Error", errorString); 835 mEventFacade.postEvent(mEventType + index + "onScanFailed", 836 mResults.clone()); 837 mResults.clear(); 838 } 839 840 @Override onScanResult(int callbackType, ScanResult result)841 public void onScanResult(int callbackType, ScanResult result) { 842 Log.d("bluetooth_le_scan change onUpdate " + mEventType + " " + index); 843 mResults.putInt("ID", index); 844 mResults.putInt("CallbackType", callbackType); 845 mResults.putString("Type", "onScanResult"); 846 mResults.putParcelable("Result", result); 847 mEventFacade.postEvent(mEventType + index + "onScanResults", mResults.clone()); 848 mResults.clear(); 849 } 850 851 @Override onBatchScanResults(List<ScanResult> results)852 public void onBatchScanResults(List<ScanResult> results) { 853 Log.d("reportResult " + mEventType + " " + index); 854 mResults.putLong("Timestamp", System.currentTimeMillis() / 1000); 855 mResults.putInt("ID", index); 856 mResults.putString("Type", "onBatchScanResults"); 857 mResults.putParcelableList("Results", results); 858 mEventFacade.postEvent(mEventType + index + "onBatchScanResult", mResults.clone()); 859 mResults.clear(); 860 } 861 } 862 863 private class myLeScanCallback implements LeScanCallback { 864 public Integer index; 865 String mEventType; 866 private final Bundle mResults; 867 myLeScanCallback(Integer idx)868 public myLeScanCallback(Integer idx) { 869 index = idx; 870 mEventType = "ClassicBleScan"; 871 mResults = new Bundle(); 872 } 873 874 @Override onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)875 public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { 876 Log.d("bluetooth_classic_le_scan " + mEventType + " " + index); 877 mResults.putParcelable("Device", device); 878 mResults.putInt("Rssi", rssi); 879 mResults.putByteArray("ScanRecord", scanRecord); 880 mResults.putString("Type", "onLeScan"); 881 mEventFacade.postEvent(mEventType + index + "onLeScan", mResults.clone()); 882 mResults.clear(); 883 } 884 } 885 886 @Override shutdown()887 public void shutdown() { 888 if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) { 889 for (myScanCallback mScanCallback : mScanCallbackList.values()) { 890 if (mScanCallback != null) { 891 try { 892 mBluetoothAdapter.getBluetoothLeScanner() 893 .stopScan(mScanCallback); 894 } catch (NullPointerException e) { 895 Log.e("Failed to stop ble scan callback.", e); 896 } 897 } 898 } 899 for (myLeScanCallback mLeScanCallback : mLeScanCallbackList.values()) { 900 if (mLeScanCallback != null) { 901 try { 902 mBluetoothAdapter.stopLeScan(mLeScanCallback); 903 } catch (NullPointerException e) { 904 Log.e("Failed to stop classic ble scan callback.", e); 905 } 906 } 907 } 908 } 909 mScanCallbackList.clear(); 910 mScanFilterList.clear(); 911 mScanSettingsList.clear(); 912 mLeScanCallbackList.clear(); 913 } 914 } 915