• 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.wifi;
18 
19 import java.util.Arrays;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Set;
23 import java.util.concurrent.Callable;
24 import java.util.concurrent.ConcurrentHashMap;
25 
26 import org.json.JSONArray;
27 import org.json.JSONException;
28 import org.json.JSONObject;
29 
30 import com.googlecode.android_scripting.Log;
31 import com.googlecode.android_scripting.MainThread;
32 import com.googlecode.android_scripting.facade.EventFacade;
33 import com.googlecode.android_scripting.facade.FacadeManager;
34 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
35 import com.googlecode.android_scripting.rpc.Rpc;
36 import com.googlecode.android_scripting.rpc.RpcOptional;
37 import com.googlecode.android_scripting.rpc.RpcParameter;
38 
39 import android.app.Service;
40 import android.content.Context;
41 import android.net.wifi.ScanResult;
42 import android.net.wifi.WifiScanner;
43 import android.net.wifi.WifiScanner.BssidInfo;
44 import android.net.wifi.WifiScanner.ChannelSpec;
45 import android.net.wifi.WifiScanner.ScanData;
46 import android.net.wifi.WifiScanner.ScanSettings;
47 import android.os.Bundle;
48 import android.os.SystemClock;
49 import android.provider.Settings.Global;
50 import android.provider.Settings.SettingNotFoundException;
51 
52 /**
53  * WifiScanner functions.
54  */
55 public class WifiScannerFacade extends RpcReceiver {
56     private final Service mService;
57     private final EventFacade mEventFacade;
58     private final WifiScanner mScan;
59     // These counters are just for indexing;
60     // they do not represent the total number of listeners
61     private static int WifiScanListenerCnt;
62     private static int WifiChangeListenerCnt;
63     private static int WifiBssidListenerCnt;
64     private final ConcurrentHashMap<Integer, WifiScanListener> scanListeners;
65     private final ConcurrentHashMap<Integer, WifiScanListener> scanBackgroundListeners;
66     private final ConcurrentHashMap<Integer, ChangeListener> trackChangeListeners;
67     private final ConcurrentHashMap<Integer, WifiBssidListener> trackBssidListeners;
68     private static ConcurrentHashMap<Integer, ScanResult[]> wifiScannerResultList;
69     private static ConcurrentHashMap<Integer, ScanData[]> wifiScannerDataList;
70 
WifiScannerFacade(FacadeManager manager)71     public WifiScannerFacade(FacadeManager manager) {
72         super(manager);
73         mService = manager.getService();
74         mScan = (WifiScanner) mService.getSystemService(Context.WIFI_SCANNING_SERVICE);
75         mEventFacade = manager.getReceiver(EventFacade.class);
76         scanListeners = new ConcurrentHashMap<Integer, WifiScanListener>();
77         scanBackgroundListeners = new ConcurrentHashMap<Integer, WifiScanListener>();
78         trackChangeListeners = new ConcurrentHashMap<Integer, ChangeListener>();
79         trackBssidListeners = new ConcurrentHashMap<Integer, WifiBssidListener>();
80         wifiScannerResultList = new ConcurrentHashMap<Integer, ScanResult[]>();
81         wifiScannerDataList = new ConcurrentHashMap<Integer, ScanData[]>();
82     }
83 
getWifiScanResult(Integer listenerIndex)84     public static List<ScanResult> getWifiScanResult(Integer listenerIndex) {
85         ScanResult[] sr = wifiScannerResultList.get(listenerIndex);
86         return Arrays.asList(sr);
87     }
88 
89     private class WifiActionListener implements WifiScanner.ActionListener {
90         private final Bundle mResults;
91         public int mIndex;
92         protected String mEventType;
93         private long startScanElapsedRealTime;
94 
WifiActionListener(String type, int idx, Bundle resultBundle, long startScanERT)95         public WifiActionListener(String type, int idx, Bundle resultBundle, long startScanERT) {
96             this.mIndex = idx;
97             this.mEventType = type;
98             this.mResults = resultBundle;
99             this.startScanElapsedRealTime = startScanERT;
100         }
101 
102         @Override
onSuccess()103         public void onSuccess() {
104             Log.d("onSuccess " + mEventType + " " + mIndex);
105             mResults.putString("Type", "onSuccess");
106             mResults.putInt("Index", mIndex);
107             mResults.putLong("ScanElapsedRealtime", startScanElapsedRealTime);
108             mEventFacade.postEvent(mEventType + mIndex + "onSuccess", mResults.clone());
109             mResults.clear();
110         }
111 
112         @Override
onFailure(int reason, String description)113         public void onFailure(int reason, String description) {
114             Log.d("onFailure " + mEventType + " " + mIndex);
115             mResults.putString("Type", "onFailure");
116             mResults.putInt("Index", mIndex);
117             mResults.putInt("Reason", reason);
118             mResults.putString("Description", description);
119             mEventFacade.postEvent(mEventType + mIndex + "onFailure", mResults.clone());
120             mResults.clear();
121         }
122 
reportResult(ScanResult[] results, String type)123         public void reportResult(ScanResult[] results, String type) {
124             Log.d("reportResult " + mEventType + " " + mIndex);
125             mResults.putInt("Index", mIndex);
126             mResults.putLong("ResultElapsedRealtime", SystemClock.elapsedRealtime());
127             mResults.putString("Type", type);
128             mResults.putParcelableArray("Results", results);
129             mEventFacade.postEvent(mEventType + mIndex + type, mResults.clone());
130             mResults.clear();
131         }
132     }
133 
134     /**
135      * Constructs a wifiScanListener obj and returns it
136      *
137      * @return WifiScanListener
138      */
genWifiScanListener()139     private WifiScanListener genWifiScanListener() {
140         WifiScanListener mWifiScannerListener = MainThread.run(mService,
141                 new Callable<WifiScanListener>() {
142                     @Override
143                     public WifiScanListener call() throws Exception {
144                         return new WifiScanListener();
145                     }
146                 });
147         scanListeners.put(mWifiScannerListener.mIndex, mWifiScannerListener);
148         return mWifiScannerListener;
149     }
150 
151     /**
152      * Constructs a wifiScanListener obj for background scan and returns it
153      *
154      * @return WifiScanListener
155      */
genBackgroundWifiScanListener()156     private WifiScanListener genBackgroundWifiScanListener() {
157         WifiScanListener mWifiScannerListener = MainThread.run(mService,
158                 new Callable<WifiScanListener>() {
159                     @Override
160                     public WifiScanListener call() throws Exception {
161                         return new WifiScanListener();
162                     }
163                 });
164         scanBackgroundListeners.put(mWifiScannerListener.mIndex, mWifiScannerListener);
165         return mWifiScannerListener;
166     }
167 
168     private class WifiScanListener implements WifiScanner.ScanListener {
169         private static final String mEventType = "WifiScannerScan";
170         protected final Bundle mScanResults;
171         protected final Bundle mScanData;
172         private final WifiActionListener mWAL;
173         public int mIndex;
174 
WifiScanListener()175         public WifiScanListener() {
176             mScanResults = new Bundle();
177             mScanData = new Bundle();
178             WifiScanListenerCnt += 1;
179             mIndex = WifiScanListenerCnt;
180             mWAL = new WifiActionListener(mEventType, mIndex, mScanResults,
181                     SystemClock.elapsedRealtime());
182         }
183 
184         @Override
onSuccess()185         public void onSuccess() {
186             mWAL.onSuccess();
187         }
188 
189         @Override
onFailure(int reason, String description)190         public void onFailure(int reason, String description) {
191             scanListeners.remove(mIndex);
192             mWAL.onFailure(reason, description);
193         }
194 
195         @Override
onPeriodChanged(int periodInMs)196         public void onPeriodChanged(int periodInMs) {
197             Log.d("onPeriodChanged " + mEventType + " " + mIndex);
198             mScanResults.putString("Type", "onPeriodChanged");
199             mScanResults.putInt("NewPeriod", periodInMs);
200             mEventFacade.postEvent(mEventType + mIndex, mScanResults.clone());
201             mScanResults.clear();
202         }
203 
204         @Override
onFullResult(ScanResult fullScanResult)205         public void onFullResult(ScanResult fullScanResult) {
206             Log.d("onFullResult WifiScanListener " + mIndex);
207             mWAL.reportResult(new ScanResult[] {
208                     fullScanResult
209             }, "onFullResult");
210         }
211 
onResults(ScanData[] results)212         public void onResults(ScanData[] results) {
213             Log.d("onResult WifiScanListener " + mIndex);
214             wifiScannerDataList.put(mIndex, results);
215             mScanData.putInt("Index", mIndex);
216             mScanData.putLong("ResultElapsedRealtime", SystemClock.elapsedRealtime());
217             mScanData.putString("Type", "onResults");
218             mScanData.putParcelableArray("Results", results);
219             mEventFacade.postEvent(mEventType + mIndex + "onResults", mScanData.clone());
220             mScanData.clear();
221         }
222     }
223 
224     /**
225      * Constructs a ChangeListener obj and returns it
226      *
227      * @return ChangeListener
228      */
genWifiChangeListener()229     private ChangeListener genWifiChangeListener() {
230         ChangeListener mWifiChangeListener = MainThread.run(mService,
231                 new Callable<ChangeListener>() {
232                     @Override
233                     public ChangeListener call() throws Exception {
234                         return new ChangeListener();
235                     }
236                 });
237         trackChangeListeners.put(mWifiChangeListener.mIndex, mWifiChangeListener);
238         return mWifiChangeListener;
239     }
240 
241     private class ChangeListener implements WifiScanner.WifiChangeListener {
242         private static final String mEventType = "WifiScannerChange";
243         protected final Bundle mResults;
244         private final WifiActionListener mWAL;
245         public int mIndex;
246 
ChangeListener()247         public ChangeListener() {
248             mResults = new Bundle();
249             WifiChangeListenerCnt += 1;
250             mIndex = WifiChangeListenerCnt;
251             mWAL = new WifiActionListener(mEventType, mIndex, mResults,
252                     SystemClock.elapsedRealtime());
253         }
254 
255         @Override
onSuccess()256         public void onSuccess() {
257             mWAL.onSuccess();
258         }
259 
260         @Override
onFailure(int reason, String description)261         public void onFailure(int reason, String description) {
262             trackChangeListeners.remove(mIndex);
263             mWAL.onFailure(reason, description);
264         }
265 
266         /**
267          * indicates that changes were detected in wifi environment
268          *
269          * @param results indicate the access points that exhibited change
270          */
271         @Override
onChanging(ScanResult[] results)272         public void onChanging(ScanResult[] results) { /* changes are found */
273             mWAL.reportResult(results, "onChanging");
274         }
275 
276         /**
277          * indicates that no wifi changes are being detected for a while
278          *
279          * @param results indicate the access points that are bing monitored for change
280          */
281         @Override
onQuiescence(ScanResult[] results)282         public void onQuiescence(ScanResult[] results) { /* changes settled down */
283             mWAL.reportResult(results, "onQuiescence");
284         }
285     }
286 
genWifiBssidListener()287     private WifiBssidListener genWifiBssidListener() {
288         WifiBssidListener mWifiBssidListener = MainThread.run(mService,
289                 new Callable<WifiBssidListener>() {
290                     @Override
291                     public WifiBssidListener call() throws Exception {
292                         return new WifiBssidListener();
293                     }
294                 });
295         trackBssidListeners.put(mWifiBssidListener.mIndex, mWifiBssidListener);
296         return mWifiBssidListener;
297     }
298 
299     private class WifiBssidListener implements WifiScanner.BssidListener {
300         private static final String mEventType = "WifiScannerBssid";
301         protected final Bundle mResults;
302         private final WifiActionListener mWAL;
303         public int mIndex;
304 
WifiBssidListener()305         public WifiBssidListener() {
306             mResults = new Bundle();
307             WifiBssidListenerCnt += 1;
308             mIndex = WifiBssidListenerCnt;
309             mWAL = new WifiActionListener(mEventType, mIndex, mResults,
310                     SystemClock.elapsedRealtime());
311         }
312 
313         @Override
onSuccess()314         public void onSuccess() {
315             mWAL.onSuccess();
316         }
317 
318         @Override
onFailure(int reason, String description)319         public void onFailure(int reason, String description) {
320             trackBssidListeners.remove(mIndex);
321             mWAL.onFailure(reason, description);
322         }
323 
324         @Override
onFound(ScanResult[] results)325         public void onFound(ScanResult[] results) {
326             mWAL.reportResult(results, "onFound");
327         }
328 
329         @Override
onLost(ScanResult[] results)330         public void onLost(ScanResult[] results) {
331             mWAL.reportResult(results, "onLost");
332         }
333     }
334 
parseScanSettings(JSONObject j)335     private ScanSettings parseScanSettings(JSONObject j) throws JSONException {
336         if (j == null) {
337             return null;
338         }
339         ScanSettings result = new ScanSettings();
340         if (j.has("band")) {
341             result.band = j.optInt("band");
342         }
343         if (j.has("channels")) {
344             JSONArray chs = j.getJSONArray("channels");
345             ChannelSpec[] channels = new ChannelSpec[chs.length()];
346             for (int i = 0; i < channels.length; i++) {
347                 channels[i] = new ChannelSpec(chs.getInt(i));
348             }
349             result.channels = channels;
350         }
351         if (j.has("maxScansToCache")) {
352             result.maxScansToCache = j.getInt("maxScansToCache");
353         }
354         /* periodInMs and reportEvents are required */
355         result.periodInMs = j.getInt("periodInMs");
356         if (j.has("maxPeriodInMs")) {
357             result.maxPeriodInMs = j.getInt("maxPeriodInMs");
358         }
359         if (j.has("stepCount")) {
360             result.stepCount = j.getInt("stepCount");
361         }
362         result.reportEvents = j.getInt("reportEvents");
363         if (j.has("numBssidsPerScan")) {
364             result.numBssidsPerScan = j.getInt("numBssidsPerScan");
365         }
366         return result;
367     }
368 
parseBssidInfo(JSONArray jBssids)369     private BssidInfo[] parseBssidInfo(JSONArray jBssids) throws JSONException {
370         BssidInfo[] bssids = new BssidInfo[jBssids.length()];
371         for (int i = 0; i < bssids.length; i++) {
372             JSONObject bi = (JSONObject) jBssids.get(i);
373             BssidInfo bssidInfo = new BssidInfo();
374             bssidInfo.bssid = bi.getString("BSSID");
375             bssidInfo.high = bi.getInt("high");
376             bssidInfo.low = bi.getInt("low");
377             if (bi.has("frequencyHint")) {
378                 bssidInfo.frequencyHint = bi.getInt("frequencyHint");
379             }
380             bssids[i] = bssidInfo;
381         }
382         return bssids;
383     }
384 
385     /**
386      * Starts periodic WifiScanner scan
387      *
388      * @param scanSettings
389      * @return the id of the scan listener associated with this scan
390      * @throws JSONException
391      */
392     @Rpc(description = "Starts a WifiScanner Background scan")
wifiScannerStartBackgroundScan( @pcParametername = "scanSettings") JSONObject scanSettings)393     public Integer wifiScannerStartBackgroundScan(
394             @RpcParameter(name = "scanSettings") JSONObject scanSettings)
395                     throws JSONException {
396         ScanSettings ss = parseScanSettings(scanSettings);
397         Log.d("startWifiScannerScan with " + ss.channels);
398         WifiScanListener listener = genBackgroundWifiScanListener();
399         mScan.startBackgroundScan(ss, listener);
400         return listener.mIndex;
401     }
402 
403     /**
404      * Get currently available scan results on appropriate listeners
405      *
406      * @return true if all scan results were reported correctly
407      * @throws JSONException
408      */
409     @Rpc(description = "Get currently available scan results on appropriate listeners")
wifiScannerGetScanResults()410     public Boolean wifiScannerGetScanResults() throws JSONException {
411         mScan.getScanResults();
412         return true;
413     }
414 
415     /**
416      * Stops a WifiScanner scan
417      *
418      * @param listenerIndex the id of the scan listener whose scan to stop
419      * @throws Exception
420      */
421     @Rpc(description = "Stops an ongoing  WifiScanner Background scan")
wifiScannerStopBackgroundScan( @pcParametername = "listener") Integer listenerIndex)422     public void wifiScannerStopBackgroundScan(
423             @RpcParameter(name = "listener") Integer listenerIndex)
424                     throws Exception {
425         if (!scanBackgroundListeners.containsKey(listenerIndex)) {
426             throw new Exception("Background scan session " + listenerIndex + " does not exist");
427         }
428         WifiScanListener listener = scanBackgroundListeners.get(listenerIndex);
429         Log.d("stopWifiScannerScan listener " + listener.mIndex);
430         mScan.stopBackgroundScan(listener);
431         wifiScannerResultList.remove(listenerIndex);
432         scanBackgroundListeners.remove(listenerIndex);
433     }
434 
435     /**
436      * Starts periodic WifiScanner scan
437      *
438      * @param scanSettings
439      * @return the id of the scan listener associated with this scan
440      * @throws JSONException
441      */
442     @Rpc(description = "Starts a WifiScanner single scan")
wifiScannerStartScan( @pcParametername = "scanSettings") JSONObject scanSettings)443     public Integer wifiScannerStartScan(
444             @RpcParameter(name = "scanSettings") JSONObject scanSettings)
445                     throws JSONException {
446         ScanSettings ss = parseScanSettings(scanSettings);
447         Log.d("startWifiScannerScan with " + ss.channels);
448         WifiScanListener listener = genWifiScanListener();
449         mScan.startScan(ss, listener);
450         return listener.mIndex;
451     }
452 
453     /**
454      * Stops a WifiScanner scan
455      *
456      * @param listenerIndex the id of the scan listener whose scan to stop
457      * @throws Exception
458      */
459     @Rpc(description = "Stops an ongoing  WifiScanner Single scan")
wifiScannerStopScan(@pcParametername = "listener") Integer listenerIndex)460     public void wifiScannerStopScan(@RpcParameter(name = "listener") Integer listenerIndex)
461             throws Exception {
462         if (!scanListeners.containsKey(listenerIndex)) {
463             throw new Exception("Single scan session " + listenerIndex + " does not exist");
464         }
465         WifiScanListener listener = scanListeners.get(listenerIndex);
466         Log.d("stopWifiScannerScan listener " + listener.mIndex);
467         mScan.stopScan(listener);
468         wifiScannerResultList.remove(listener.mIndex);
469         scanListeners.remove(listenerIndex);
470     }
471 
472     /** RPC Methods */
473     @Rpc(description = "Returns the channels covered by the specified band number.")
wifiScannerGetAvailableChannels( @pcParametername = "band") Integer band)474     public List<Integer> wifiScannerGetAvailableChannels(
475             @RpcParameter(name = "band") Integer band) {
476         return mScan.getAvailableChannels(band);
477     }
478 
479     /**
480      * Starts tracking wifi changes
481      *
482      * @return the id of the change listener associated with this track
483      * @throws Exception
484      */
485     @Rpc(description = "Starts tracking wifi changes")
wifiScannerStartTrackingChange()486     public Integer wifiScannerStartTrackingChange() throws Exception {
487         ChangeListener listener = genWifiChangeListener();
488         mScan.startTrackingWifiChange(listener);
489         return listener.mIndex;
490     }
491 
492     /**
493      * Stops tracking wifi changes
494      *
495      * @param listenerIndex the id of the change listener whose track to stop
496      * @throws Exception
497      */
498     @Rpc(description = "Stops tracking wifi changes")
wifiScannerStopTrackingChange( @pcParametername = "listener") Integer listenerIndex)499     public void wifiScannerStopTrackingChange(
500             @RpcParameter(name = "listener") Integer listenerIndex) throws Exception {
501         if (!trackChangeListeners.containsKey(listenerIndex)) {
502             throw new Exception("Wifi change tracking session " + listenerIndex
503                     + " does not exist");
504         }
505         ChangeListener listener = trackChangeListeners.get(listenerIndex);
506         mScan.stopTrackingWifiChange(listener);
507         trackChangeListeners.remove(listenerIndex);
508     }
509 
510     /**
511      * Starts tracking changes of the specified bssids.
512      *
513      * @param bssidInfos An array of json strings, each representing a BssidInfo object.
514      * @param apLostThreshold
515      * @return The index of the listener used to start the tracking.
516      * @throws JSONException
517      */
518     @Rpc(description = "Starts tracking changes of the specified bssids.")
wifiScannerStartTrackingBssids( @pcParametername = "bssidInfos") JSONArray bssidInfos, @RpcParameter(name = "apLostThreshold") Integer apLostThreshold)519     public Integer wifiScannerStartTrackingBssids(
520             @RpcParameter(name = "bssidInfos") JSONArray bssidInfos,
521             @RpcParameter(name = "apLostThreshold") Integer apLostThreshold) throws JSONException {
522         BssidInfo[] bssids = parseBssidInfo(bssidInfos);
523         WifiBssidListener listener = genWifiBssidListener();
524         mScan.startTrackingBssids(bssids, apLostThreshold, listener);
525         return listener.mIndex;
526     }
527 
528     /**
529      * Stops tracking the list of APs associated with the input listener
530      *
531      * @param listenerIndex the id of the bssid listener whose track to stop
532      * @throws Exception
533      */
534     @Rpc(description = "Stops tracking changes in the APs on the list")
wifiScannerStopTrackingBssids( @pcParametername = "listener") Integer listenerIndex)535     public void wifiScannerStopTrackingBssids(
536             @RpcParameter(name = "listener") Integer listenerIndex) throws Exception {
537         if (!trackBssidListeners.containsKey(listenerIndex)) {
538             throw new Exception("Bssid tracking session " + listenerIndex + " does not exist");
539         }
540         WifiBssidListener listener = trackBssidListeners.get(listenerIndex);
541         mScan.stopTrackingBssids(listener);
542         trackBssidListeners.remove(listenerIndex);
543     }
544 
545     @Rpc(description = "Toggle the 'WiFi scan always available' option. If an input is given, the "
546             + "option is set to what the input boolean indicates.")
wifiScannerToggleAlwaysAvailable( @pcParametername = "alwaysAvailable") @pcOptional Boolean alwaysAvailable)547     public void wifiScannerToggleAlwaysAvailable(
548             @RpcParameter(name = "alwaysAvailable") @RpcOptional Boolean alwaysAvailable)
549                     throws SettingNotFoundException {
550         int new_state = 0;
551         if (alwaysAvailable == null) {
552             int current_state = Global.getInt(mService.getContentResolver(),
553                     Global.WIFI_SCAN_ALWAYS_AVAILABLE);
554             new_state = current_state ^ 0x1;
555         } else {
556             new_state = alwaysAvailable ? 1 : 0;
557         }
558         Global.putInt(mService.getContentResolver(), Global.WIFI_SCAN_ALWAYS_AVAILABLE, new_state);
559     }
560 
561     @Rpc(description = "Returns true if WiFi scan is always available, false otherwise.")
wifiScannerIsAlwaysAvailable()562     public Boolean wifiScannerIsAlwaysAvailable() throws SettingNotFoundException {
563         int current_state = Global.getInt(mService.getContentResolver(),
564                 Global.WIFI_SCAN_ALWAYS_AVAILABLE);
565         if (current_state == 1) {
566             return true;
567         }
568         return false;
569     }
570 
571     @Rpc(description = "Returns a list of mIndexes of existing listeners")
wifiGetCurrentScanIndexes()572     public Set<Integer> wifiGetCurrentScanIndexes() {
573         return scanListeners.keySet();
574     }
575 
576     /**
577      * Starts tracking wifi changes
578      *
579      * @return the id of the change listener associated with this track
580      * @throws Exception
581      */
582     @Rpc(description = "Starts tracking wifi changes with track settings")
wifiScannerStartTrackingChangeWithSetting( @pcParametername = "trackSettings") JSONArray bssidSettings, @RpcParameter(name = "rssiSS") Integer rssiSS, @RpcParameter(name = "lostApSS") Integer lostApSS, @RpcParameter(name = "unchangedSS") Integer unchangedSS, @RpcParameter(name = "minApsBreachingThreshold") Integer minApsBreachingThreshold, @RpcParameter(name = "periodInMs") Integer periodInMs)583     public Integer wifiScannerStartTrackingChangeWithSetting(
584             @RpcParameter(name = "trackSettings") JSONArray bssidSettings,
585             @RpcParameter(name = "rssiSS") Integer rssiSS,
586             @RpcParameter(name = "lostApSS") Integer lostApSS,
587             @RpcParameter(name = "unchangedSS") Integer unchangedSS,
588             @RpcParameter(name = "minApsBreachingThreshold") Integer minApsBreachingThreshold,
589             @RpcParameter(name = "periodInMs") Integer periodInMs) throws Exception {
590         Log.d("starting change track with track settings");
591         BssidInfo[] bssids = parseBssidInfo(bssidSettings);
592         mScan.configureWifiChange(rssiSS, lostApSS, unchangedSS, minApsBreachingThreshold,
593               periodInMs, bssids);
594         ChangeListener listener = genWifiChangeListener();
595         mScan.startTrackingWifiChange(listener);
596         return listener.mIndex;
597     }
598 
599     /**
600      * Shuts down all activities associated with WifiScanner
601      */
602     @Rpc(description = "Shuts down all WifiScanner activities and remove listeners.")
wifiScannerShutdown()603     public void wifiScannerShutdown() {
604         this.shutdown();
605     }
606 
607     /**
608      * Stops all activity
609      */
610     @Override
shutdown()611     public void shutdown() {
612         try {
613             if (!scanListeners.isEmpty()) {
614                 Iterator<ConcurrentHashMap.Entry<Integer, WifiScanListener>> iter = scanListeners
615                         .entrySet().iterator();
616                 while (iter.hasNext()) {
617                     ConcurrentHashMap.Entry<Integer, WifiScanListener> entry = iter.next();
618                     this.wifiScannerStopScan(entry.getKey());
619                 }
620             }
621             if (!scanBackgroundListeners.isEmpty()) {
622                 Iterator<ConcurrentHashMap.Entry<Integer, WifiScanListener>> iter = scanBackgroundListeners
623                         .entrySet().iterator();
624                 while (iter.hasNext()) {
625                     ConcurrentHashMap.Entry<Integer, WifiScanListener> entry = iter.next();
626                     this.wifiScannerStopBackgroundScan(entry.getKey());
627                 }
628             }
629             if (!trackChangeListeners.isEmpty()) {
630                 Iterator<ConcurrentHashMap.Entry<Integer, ChangeListener>> iter = trackChangeListeners
631                         .entrySet().iterator();
632                 while (iter.hasNext()) {
633                     ConcurrentHashMap.Entry<Integer, ChangeListener> entry = iter.next();
634                     this.wifiScannerStopTrackingChange(entry.getKey());
635                 }
636             }
637             if (!trackBssidListeners.isEmpty()) {
638                 Iterator<ConcurrentHashMap.Entry<Integer, WifiBssidListener>> iter = trackBssidListeners
639                         .entrySet().iterator();
640                 while (iter.hasNext()) {
641                     ConcurrentHashMap.Entry<Integer, WifiBssidListener> entry = iter.next();
642                     this.wifiScannerStopTrackingBssids(entry.getKey());
643                 }
644             }
645         } catch (Exception e) {
646             Log.e("Shutdown failed: " + e.toString());
647         }
648     }
649 }
650