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