• 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,
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")
bleStartClassicBleScan( @pcParametername = "leCallbackIndex") Integer leCallbackIndex )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")
bleStartClassicBleScanWithServiceUuids( @pcParametername = "leCallbackIndex") Integer leCallbackIndex, @RpcParameter(name = "serviceUuids") String[] serviceUuidList )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")
bleFlushPendingScanResults( @pcParametername = "callbackIndex") Integer callbackIndex )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")
bleSetScanSettingsCallbackType( @pcParametername = "callbackType") Integer callbackType)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")
bleSetScanSettingsReportDelayMillis( @pcParametername = "reportDelayMillis") Long reportDelayMillis)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")
bleSetScanSettingsScanMode( @pcParametername = "scanMode") Integer scanMode)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")
bleSetScanSettingsLegacy( @pcParametername = "legacy") Boolean legacy)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")
bleSetScanSettingsPhy( @pcParametername = "phy") Integer phy)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")
bleSetScanSettingsResultType( @pcParametername = "scanResultType") Integer scanResultType)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")
bleGetScanSettingsCallbackType( @pcParametername = "index") Integer index )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")
bleGetScanSettingsReportDelayMillis( @pcParametername = "index") Integer index)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")
bleGetScanSettingsScanMode( @pcParametername = "index") Integer index)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")
bleGetScanSettingsScanResultType( @pcParametername = "index") Integer index)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")
bleGetScanFilterManufacturerId( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleGetScanFilterDeviceAddress( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleGetScanFilterDeviceName( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleGetScanFilterManufacturerData( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleGetScanFilterManufacturerDataMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleGetScanFilterServiceData( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleGetScanFilterServiceDataMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleGetScanFilterServiceUuid( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleGetScanFilterServiceUuidMask( @pcParametername = "index") Integer index, @RpcParameter(name = "filterIndex") Integer filterIndex)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")
bleSetScanFilterDeviceAddress( @pcParametername = "macAddress") String macAddress )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")
bleSetScanFilterManufacturerData( @pcParametername = "manufacturerDataId") Integer manufacturerDataId, @RpcParameter(name = "manufacturerData") byte[] manufacturerData, @RpcParameter(name = "manufacturerDataMask") @RpcOptional byte[] manufacturerDataMask )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 ")
bleSetScanFilterServiceData( @pcParametername = "serviceUuid") String serviceUuid, @RpcParameter(name = "serviceData") byte[] serviceData, @RpcParameter(name = "serviceDataMask") @RpcOptional byte[] serviceDataMask )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")
bleSetScanFilterServiceUuid( @pcParametername = "serviceUuid") String serviceUuid, @RpcParameter(name = "serviceMask") @RpcOptional String serviceMask )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")
bleSetScanFilterDeviceName( @pcParametername = "name") String 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")
bleSetScanSettingsMatchMode( @pcParametername = "mode") Integer 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")
bleGetScanSettingsMatchMode( @pcParametername = "scanSettingsIndex") Integer scanSettingsIndex )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")
bleSetScanSettingsNumOfMatches( @pcParametername = "matches") Integer 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")
bleGetScanSettingsNumberOfMatches( @pcParametername = "scanSettingsIndex") Integer scanSettingsIndex)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 
myScanCallback(Integer idx)861         public myScanCallback(Integer idx) {
862             index = idx;
863             mEventType = "BleScan";
864             mResults = new Bundle();
865         }
866 
867         @Override
onScanFailed(int errorCode)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
onScanResult(int callbackType, ScanResult result)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
onBatchScanResults(List<ScanResult> results)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 
myLeScanCallback(Integer idx)924         public myLeScanCallback(Integer idx) {
925             index = idx;
926             mEventType = "ClassicBleScan";
927             mResults = new Bundle();
928         }
929 
930         @Override
onLeScan( BluetoothDevice device, int rssi, byte[] scanRecord)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
shutdown()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