Home | History | Annotate | Download | only in bluetooth
      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