• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 legacy mode
352      * @param legacy Wether scan is legacy.
353      */
354     @Rpc(description = "Set the scan setting's legacy mode")
bleSetScanSettingsLegacy( @pcParametername = "legacy") Boolean legacy)355     public void bleSetScanSettingsLegacy(
356             @RpcParameter(name = "legacy")
357             Boolean legacy) {
358         mScanSettingsBuilder.setLegacy(legacy);
359     }
360 
361     /**
362      * Set the scan setting's phy mode
363      * @param phy
364      */
365     @Rpc(description = "Set the scan setting's phy mode")
bleSetScanSettingsPhy( @pcParametername = "phy") Integer phy)366     public void bleSetScanSettingsPhy(
367             @RpcParameter(name = "phy")
368             Integer phy) {
369         mScanSettingsBuilder.setPhy(phy);
370     }
371 
372     /**
373      * Set the scan setting's scan result type
374      * @param scanResultType Bluetooth LE scan result type
375      */
376     @Rpc(description = "Set the scan setting's scan result type")
bleSetScanSettingsResultType( @pcParametername = "scanResultType") Integer scanResultType)377     public void bleSetScanSettingsResultType(
378             @RpcParameter(name = "scanResultType")
379             Integer scanResultType) {
380         mScanSettingsBuilder.setScanResultType(scanResultType);
381     }
382     /**
383      * Get ScanSetting's callback type
384      *
385      * @param index the ScanSetting object to use
386      * @return the ScanSetting's callback type
387      * @throws Exception
388      */
389     @Rpc(description = "Get ScanSetting's callback type")
bleGetScanSettingsCallbackType( @pcParametername = "index") Integer index )390     public Integer bleGetScanSettingsCallbackType(
391             @RpcParameter(name = "index")
392             Integer index
393             ) throws Exception {
394         if (mScanSettingsList.get(index) != null) {
395             ScanSettings mScanSettings = mScanSettingsList.get(index);
396             return mScanSettings.getCallbackType();
397         } else {
398             throw new Exception("Invalid index input:" + Integer.toString(index));
399         }
400     }
401 
402     /**
403      * Get ScanSetting's report delay in milli seconds
404      *
405      * @param index the ScanSetting object to useSystemClock
406      * @return the ScanSetting's report delay in milliseconds
407      * @throws Exception
408      */
409     @Rpc(description = "Get ScanSetting's report delay milliseconds")
bleGetScanSettingsReportDelayMillis( @pcParametername = "index") Integer index)410     public Long bleGetScanSettingsReportDelayMillis(
411             @RpcParameter(name = "index")
412             Integer index) throws Exception {
413         if (mScanSettingsList.get(index) != null) {
414             ScanSettings mScanSettings = mScanSettingsList.get(index);
415             return mScanSettings.getReportDelayMillis();
416         } else {
417             throw new Exception("Invalid index input:" + Integer.toString(index));
418         }
419     }
420 
421     /**
422      * Get ScanSetting's scan mode
423      *
424      * @param index the ScanSetting object to use
425      * @return the ScanSetting's scan mode
426      * @throws Exception
427      */
428     @Rpc(description = "Get ScanSetting's scan mode")
bleGetScanSettingsScanMode( @pcParametername = "index") Integer index)429     public Integer bleGetScanSettingsScanMode(
430             @RpcParameter(name = "index")
431             Integer index) throws Exception {
432         if (mScanSettingsList.get(index) != null) {
433             ScanSettings mScanSettings = mScanSettingsList.get(index);
434             return mScanSettings.getScanMode();
435         } else {
436             throw new Exception("Invalid index input:" + Integer.toString(index));
437         }
438     }
439 
440     /**
441      * Get ScanSetting's scan result type
442      *
443      * @param index the ScanSetting object to use
444      * @return the ScanSetting's scan result type
445      * @throws Exception
446      */
447     @Rpc(description = "Get ScanSetting's scan result type")
bleGetScanSettingsScanResultType( @pcParametername = "index") Integer index)448     public Integer bleGetScanSettingsScanResultType(
449             @RpcParameter(name = "index")
450             Integer index) throws Exception {
451         if (mScanSettingsList.get(index) != null) {
452             ScanSettings mScanSettings = mScanSettingsList.get(index);
453             return mScanSettings.getScanResultType();
454         } else {
455             throw new Exception("Invalid index input:" + Integer.toString(index));
456         }
457     }
458 
459     /**
460      * Get ScanFilter's Manufacturer Id
461      *
462      * @param index the ScanFilter object to use
463      * @return the ScanFilter's manufacturer id
464      * @throws Exception
465      */
466     @Rpc(description = "Get ScanFilter's Manufacturer Id")
bleGetScanFilterManufacturerId( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)467     public Integer bleGetScanFilterManufacturerId(
468             @RpcParameter(name = "index")
469             Integer index,
470             @RpcParameter(name = "filterIndex")
471             Integer filterIndex)
472             throws Exception {
473         if (mScanFilterList.get(index) != null) {
474             if (mScanFilterList.get(index).get(filterIndex) != null) {
475                 return mScanFilterList.get(index)
476                         .get(filterIndex).getManufacturerId();
477             } else {
478                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
479             }
480         } else {
481             throw new Exception("Invalid index input:" + Integer.toString(index));
482         }
483     }
484 
485     /**
486      * Get ScanFilter's device address
487      *
488      * @param index the ScanFilter object to use
489      * @return the ScanFilter's device address
490      * @throws Exception
491      */
492     @Rpc(description = "Get ScanFilter's device address")
bleGetScanFilterDeviceAddress( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)493     public String bleGetScanFilterDeviceAddress(
494             @RpcParameter(name = "index")
495             Integer index,
496             @RpcParameter(name = "filterIndex")
497             Integer filterIndex)
498             throws Exception {
499         if (mScanFilterList.get(index) != null) {
500             if (mScanFilterList.get(index).get(filterIndex) != null) {
501                 return mScanFilterList.get(index).get(filterIndex).getDeviceAddress();
502             } else {
503                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
504             }
505         } else {
506             throw new Exception("Invalid index input:" + Integer.toString(index));
507         }
508     }
509 
510     /**
511      * Get ScanFilter's device name
512      *
513      * @param index the ScanFilter object to use
514      * @return the ScanFilter's device name
515      * @throws Exception
516      */
517     @Rpc(description = "Get ScanFilter's device name")
bleGetScanFilterDeviceName( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)518     public String bleGetScanFilterDeviceName(
519             @RpcParameter(name = "index")
520             Integer index,
521             @RpcParameter(name = "filterIndex")
522             Integer filterIndex)
523             throws Exception {
524         if (mScanFilterList.get(index) != null) {
525             if (mScanFilterList.get(index).get(filterIndex) != null) {
526                 return mScanFilterList.get(index).get(filterIndex).getDeviceName();
527             } else {
528                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
529             }
530         } else {
531             throw new Exception("Invalid index input:" + Integer.toString(index));
532         }
533     }
534 
535     /**
536      * Get ScanFilter's manufacturer data
537      *
538      * @param index the ScanFilter object to use
539      * @return the ScanFilter's manufacturer data
540      * @throws Exception
541      */
542     @Rpc(description = "Get ScanFilter's manufacturer data")
bleGetScanFilterManufacturerData( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)543     public byte[] bleGetScanFilterManufacturerData(
544             @RpcParameter(name = "index")
545             Integer index,
546             @RpcParameter(name = "filterIndex")
547             Integer filterIndex)
548             throws Exception {
549         if (mScanFilterList.get(index) != null) {
550             if (mScanFilterList.get(index).get(filterIndex) != null) {
551                 return mScanFilterList.get(index).get(filterIndex).getManufacturerData();
552             } else {
553                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
554             }
555         } else {
556             throw new Exception("Invalid index input:" + Integer.toString(index));
557         }
558     }
559 
560     /**
561      * Get ScanFilter's manufacturer data mask
562      *
563      * @param index the ScanFilter object to use
564      * @return the ScanFilter's manufacturer data mask
565      * @throws Exception
566      */
567     @Rpc(description = "Get ScanFilter's manufacturer data mask")
bleGetScanFilterManufacturerDataMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)568     public byte[] bleGetScanFilterManufacturerDataMask(
569             @RpcParameter(name = "index")
570             Integer index,
571             @RpcParameter(name = "filterIndex")
572             Integer filterIndex)
573             throws Exception {
574         if (mScanFilterList.get(index) != null) {
575             if (mScanFilterList.get(index).get(filterIndex) != null) {
576                 return mScanFilterList.get(index).get(filterIndex).getManufacturerDataMask();
577             } else {
578                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
579             }
580         } else {
581             throw new Exception("Invalid index input:" + Integer.toString(index));
582         }
583     }
584 
585     /**
586      * Get ScanFilter's service data
587      *
588      * @param index the ScanFilter object to use
589      * @return the ScanFilter's service data
590      * @throws Exception
591      */
592     @Rpc(description = "Get ScanFilter's service data")
bleGetScanFilterServiceData( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)593     public byte[] bleGetScanFilterServiceData(
594             @RpcParameter(name = "index")
595             Integer index,
596             @RpcParameter(name = "filterIndex")
597             Integer filterIndex)
598             throws Exception {
599         if (mScanFilterList.get(index) != null) {
600             if (mScanFilterList.get(index).get(filterIndex) != null) {
601                 return mScanFilterList.get(index).get(filterIndex).getServiceData();
602             } else {
603                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
604             }
605         } else {
606             throw new Exception("Invalid index input:" + Integer.toString(index));
607         }
608     }
609 
610     /**
611      * Get ScanFilter's service data mask
612      *
613      * @param index the ScanFilter object to use
614      * @return the ScanFilter's service data mask
615      * @throws Exception
616      */
617     @Rpc(description = "Get ScanFilter's service data mask")
bleGetScanFilterServiceDataMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)618     public byte[] bleGetScanFilterServiceDataMask(
619             @RpcParameter(name = "index")
620             Integer index,
621             @RpcParameter(name = "filterIndex")
622             Integer filterIndex)
623             throws Exception {
624         if (mScanFilterList.get(index) != null) {
625             if (mScanFilterList.get(index).get(filterIndex) != null) {
626                 return mScanFilterList.get(index).get(filterIndex).getServiceDataMask();
627             } else {
628                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
629             }
630         } else {
631             throw new Exception("Invalid index input:" + Integer.toString(index));
632         }
633     }
634 
635     /**
636      * Get ScanFilter's service uuid
637      *
638      * @param index the ScanFilter object to use
639      * @return the ScanFilter's service uuid
640      * @throws Exception
641      */
642     @Rpc(description = "Get ScanFilter's service uuid")
bleGetScanFilterServiceUuid( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)643     public String bleGetScanFilterServiceUuid(
644             @RpcParameter(name = "index")
645             Integer index,
646             @RpcParameter(name = "filterIndex")
647             Integer filterIndex)
648             throws Exception {
649         if (mScanFilterList.get(index) != null) {
650             if (mScanFilterList.get(index).get(filterIndex) != null) {
651                 if (mScanFilterList.get(index).get(filterIndex).getServiceUuid() != null) {
652                     return mScanFilterList.get(index).get(filterIndex).getServiceUuid().toString();
653                 } else {
654                     throw new Exception("No Service Uuid set for filter:"
655                             + Integer.toString(filterIndex));
656                 }
657             } else {
658                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
659             }
660         } else {
661             throw new Exception("Invalid index input:" + Integer.toString(index));
662         }
663     }
664 
665     /**
666      * Get ScanFilter's service uuid mask
667      *
668      * @param index the ScanFilter object to use
669      * @return the ScanFilter's service uuid mask
670      * @throws Exception
671      */
672     @Rpc(description = "Get ScanFilter's service uuid mask")
bleGetScanFilterServiceUuidMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)673     public String bleGetScanFilterServiceUuidMask(
674             @RpcParameter(name = "index")
675             Integer index,
676             @RpcParameter(name = "filterIndex")
677             Integer filterIndex)
678             throws Exception {
679         if (mScanFilterList.get(index) != null) {
680             if (mScanFilterList.get(index).get(filterIndex) != null) {
681                 if (mScanFilterList.get(index).get(filterIndex).getServiceUuidMask() != null) {
682                     return mScanFilterList.get(index).get(filterIndex).getServiceUuidMask()
683                             .toString();
684                 } else {
685                     throw new Exception("No Service Uuid Mask set for filter:"
686                             + Integer.toString(filterIndex));
687                 }
688             } else {
689                 throw new Exception("Invalid filterIndex input:" + Integer.toString(filterIndex));
690             }
691         } else {
692             throw new Exception("Invalid index input:" + Integer.toString(index));
693         }
694     }
695 
696     /**
697      * Add filter "macAddress" to existing ScanFilter
698      *
699      * @param macAddress the macAddress to filter against
700      * @throws Exception
701      */
702     @Rpc(description = "Add filter \"macAddress\" to existing ScanFilter")
bleSetScanFilterDeviceAddress( @pcParametername = "macAddress") String macAddress )703     public void bleSetScanFilterDeviceAddress(
704             @RpcParameter(name = "macAddress")
705             String macAddress
706             ) {
707             mScanFilterBuilder.setDeviceAddress(macAddress);
708     }
709 
710     /**
711      * Add filter "manufacturereDataId and/or manufacturerData" to existing ScanFilter
712      *
713      * @param manufacturerDataId the manufacturer data id to filter against
714      * @param manufacturerDataMask the manufacturere data mask to filter against
715      * @throws Exception
716      */
717     @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 )718     public void bleSetScanFilterManufacturerData(
719             @RpcParameter(name = "manufacturerDataId")
720             Integer manufacturerDataId,
721             @RpcParameter(name = "manufacturerData")
722             byte[] manufacturerData,
723             @RpcParameter(name = "manufacturerDataMask")
724             @RpcOptional
725             byte[] manufacturerDataMask
726             ){
727         if (manufacturerDataMask != null) {
728             mScanFilterBuilder.setManufacturerData(manufacturerDataId,
729                     manufacturerData, manufacturerDataMask);
730         } else {
731             mScanFilterBuilder.setManufacturerData(manufacturerDataId,
732                     manufacturerData);
733         }
734     }
735 
736     /**
737      * Add filter "serviceData and serviceDataMask" to existing ScanFilter
738      *
739      * @param serviceData the service data to filter against
740      * @param serviceDataMask the servie data mask to filter against
741      * @throws Exception
742      */
743     @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 )744     public void bleSetScanFilterServiceData(
745             @RpcParameter(name = "serviceUuid")
746             String serviceUuid,
747             @RpcParameter(name = "serviceData")
748             byte[] serviceData,
749             @RpcParameter(name = "serviceDataMask")
750             @RpcOptional
751             byte[] serviceDataMask
752             ) {
753         if (serviceDataMask != null) {
754             mScanFilterBuilder
755                     .setServiceData(
756                             ParcelUuid.fromString(serviceUuid),
757                             serviceData, serviceDataMask);
758         } else {
759             mScanFilterBuilder.setServiceData(ParcelUuid.fromString(serviceUuid),
760                     serviceData);
761         }
762     }
763 
764     /**
765      * Add filter "serviceUuid and/or serviceMask" to existing ScanFilter
766      *
767      * @param serviceUuid the service uuid to filter against
768      * @param serviceMask the service mask to filter against
769      * @throws Exception
770      */
771     @Rpc(description = "Add filter \"serviceUuid and/or serviceMask\" to existing ScanFilter")
bleSetScanFilterServiceUuid( @pcParametername = "serviceUuid") String serviceUuid, @RpcParameter(name = "serviceMask") @RpcOptional String serviceMask )772     public void bleSetScanFilterServiceUuid(
773             @RpcParameter(name = "serviceUuid")
774             String serviceUuid,
775             @RpcParameter(name = "serviceMask")
776             @RpcOptional
777             String serviceMask
778             ) {
779         if (serviceMask != null) {
780             mScanFilterBuilder
781                     .setServiceUuid(ParcelUuid.fromString(serviceUuid),
782                             ParcelUuid.fromString(serviceMask));
783         } else {
784             mScanFilterBuilder.setServiceUuid(ParcelUuid.fromString(serviceUuid));
785         }
786     }
787 
788     /**
789      * Add filter "device name" to existing ScanFilter
790      *
791      * @param name the device name to filter against
792      * @throws Exception
793      */
794     @Rpc(description = "Sets the scan filter's device name")
bleSetScanFilterDeviceName( @pcParametername = "name") String name )795     public void bleSetScanFilterDeviceName(
796             @RpcParameter(name = "name")
797             String name
798             ) {
799             mScanFilterBuilder.setDeviceName(name);
800     }
801 
802     @Rpc(description = "Set the scan setting's match mode")
bleSetScanSettingsMatchMode( @pcParametername = "mode") Integer mode)803     public void bleSetScanSettingsMatchMode(
804             @RpcParameter(name = "mode") Integer mode) {
805         mScanSettingsBuilder.setMatchMode(mode);
806     }
807 
808     @Rpc(description = "Get the scan setting's match mode")
bleGetScanSettingsMatchMode( @pcParametername = "scanSettingsIndex") Integer scanSettingsIndex )809     public int bleGetScanSettingsMatchMode(
810             @RpcParameter(name = "scanSettingsIndex") Integer scanSettingsIndex
811             ) {
812         return mScanSettingsList.get(scanSettingsIndex).getMatchMode();
813     }
814 
815     @Rpc(description = "Set the scan setting's number of matches")
bleSetScanSettingsNumOfMatches( @pcParametername = "matches") Integer matches)816     public void bleSetScanSettingsNumOfMatches(
817             @RpcParameter(name = "matches") Integer matches) {
818         mScanSettingsBuilder.setNumOfMatches(matches);
819     }
820 
821     @Rpc(description = "Get the scan setting's number of matches")
bleGetScanSettingsNumberOfMatches( @pcParametername = "scanSettingsIndex") Integer scanSettingsIndex)822     public int bleGetScanSettingsNumberOfMatches(
823             @RpcParameter(name = "scanSettingsIndex")
824             Integer scanSettingsIndex) {
825         return  mScanSettingsList.get(scanSettingsIndex).getNumOfMatches();
826     }
827 
828     private class myScanCallback extends ScanCallback {
829         public Integer index;
830         String mEventType;
831         private final Bundle mResults;
832 
myScanCallback(Integer idx)833         public myScanCallback(Integer idx) {
834             index = idx;
835             mEventType = "BleScan";
836             mResults = new Bundle();
837         }
838 
839         @Override
onScanFailed(int errorCode)840         public void onScanFailed(int errorCode) {
841             String errorString = "UNKNOWN_ERROR_CODE";
842             if (errorCode == ScanCallback.SCAN_FAILED_ALREADY_STARTED) {
843                 errorString = "SCAN_FAILED_ALREADY_STARTED";
844             } else if (errorCode == ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED) {
845                 errorString = "SCAN_FAILED_APPLICATION_REGISTRATION_FAILED";
846             } else if (errorCode == ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED) {
847                 errorString = "SCAN_FAILED_FEATURE_UNSUPPORTED";
848             } else if (errorCode == ScanCallback.SCAN_FAILED_INTERNAL_ERROR) {
849                 errorString = "SCAN_FAILED_INTERNAL_ERROR";
850             }
851             Log.d("bluetooth_le_scan change onScanFailed " + mEventType + " " + index + " error "
852                     + errorString);
853             mResults.putInt("ID", index);
854             mResults.putString("Type", "onScanFailed");
855             mResults.putInt("ErrorCode", errorCode);
856             mResults.putString("Error", errorString);
857             mEventFacade.postEvent(mEventType + index + "onScanFailed",
858                     mResults.clone());
859             mResults.clear();
860         }
861 
862         @Override
onScanResult(int callbackType, ScanResult result)863         public void onScanResult(int callbackType, ScanResult result) {
864             Log.d("bluetooth_le_scan change onUpdate " + mEventType + " " + index);
865             mResults.putInt("ID", index);
866             mResults.putInt("CallbackType", callbackType);
867             mResults.putString("Type", "onScanResult");
868             mResults.putParcelable("Result", result);
869             mEventFacade.postEvent(mEventType + index + "onScanResults", mResults.clone());
870             mResults.clear();
871         }
872 
873         @Override
onBatchScanResults(List<ScanResult> results)874         public void onBatchScanResults(List<ScanResult> results) {
875             Log.d("reportResult " + mEventType + " " + index);
876             mResults.putLong("Timestamp", System.currentTimeMillis() / 1000);
877             mResults.putInt("ID", index);
878             mResults.putString("Type", "onBatchScanResults");
879             mResults.putParcelableList("Results", results);
880             mEventFacade.postEvent(mEventType + index + "onBatchScanResult", mResults.clone());
881             mResults.clear();
882         }
883     }
884 
885     private class myLeScanCallback implements LeScanCallback {
886         public Integer index;
887         String mEventType;
888         private final Bundle mResults;
889 
myLeScanCallback(Integer idx)890         public myLeScanCallback(Integer idx) {
891             index = idx;
892             mEventType = "ClassicBleScan";
893             mResults = new Bundle();
894         }
895 
896         @Override
onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)897         public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
898             Log.d("bluetooth_classic_le_scan " + mEventType + " " + index);
899             mResults.putParcelable("Device", device);
900             mResults.putInt("Rssi", rssi);
901             mResults.putByteArray("ScanRecord", scanRecord);
902             mResults.putString("Type", "onLeScan");
903             mEventFacade.postEvent(mEventType + index + "onLeScan", mResults.clone());
904             mResults.clear();
905         }
906     }
907 
908     @Override
shutdown()909     public void shutdown() {
910       if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
911           for (myScanCallback mScanCallback : mScanCallbackList.values()) {
912               if (mScanCallback != null) {
913                   try {
914                     mBluetoothAdapter.getBluetoothLeScanner()
915                       .stopScan(mScanCallback);
916                   } catch (NullPointerException e) {
917                     Log.e("Failed to stop ble scan callback.", e);
918                   }
919               }
920           }
921           for (myLeScanCallback mLeScanCallback : mLeScanCallbackList.values()) {
922               if (mLeScanCallback != null) {
923                   try {
924                       mBluetoothAdapter.stopLeScan(mLeScanCallback);
925                   } catch (NullPointerException e) {
926                     Log.e("Failed to stop classic ble scan callback.", e);
927                   }
928               }
929           }
930       }
931       mScanCallbackList.clear();
932       mScanFilterList.clear();
933       mScanSettingsList.clear();
934       mLeScanCallbackList.clear();
935     }
936 }
937