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