WifiAutoJoinController.java revision f22d23092ab37286a5ef9d257d5bb32c421d2669
1/* 2 * Copyright (C) 2010 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 17package com.android.server.wifi; 18 19import android.content.Context; 20 21import android.net.NetworkKey; 22import android.net.NetworkScoreManager; 23import android.net.wifi.WifiConfiguration; 24import android.net.wifi.ScanResult; 25import android.net.wifi.WifiManager; 26import android.net.wifi.WifiParser; 27 28import android.os.SystemClock; 29import android.util.Log; 30 31import java.util.Iterator; 32import java.util.HashMap; 33import java.util.List; 34import java.util.Date; 35 36/** 37 * AutoJoin controller is responsible for WiFi Connect decision 38 * 39 * It runs in the thread context of WifiStateMachine 40 * 41 */ 42public class WifiAutoJoinController { 43 44 private Context mContext; 45 private WifiStateMachine mWifiStateMachine; 46 private WifiConfigStore mWifiConfigStore; 47 private WifiTrafficPoller mWifiTrafficPoller; 48 private WifiNative mWifiNative; 49 50 private NetworkScoreManager scoreManager; 51 private WifiNetworkScoreCache mNetworkScoreCache; 52 53 54 private static final String TAG = "WifiAutoJoinController "; 55 private static final boolean DBG = true; 56 private static final boolean VDBG = false; 57 private static final boolean mStaStaSupported = false; 58 private static final int SCAN_RESULT_CACHE_SIZE = 80; 59 60 61 private HashMap<String, ScanResult> scanResultCache = 62 new HashMap<String, ScanResult>(); 63 64 WifiAutoJoinController(Context c, WifiStateMachine w, WifiConfigStore s, 65 WifiTrafficPoller t, WifiNative n) { 66 mContext = c; 67 mWifiStateMachine = w; 68 mWifiConfigStore = s; 69 mWifiTrafficPoller = t; 70 mWifiNative = n; 71 mNetworkScoreCache = null; 72 scoreManager = (NetworkScoreManager) mContext.getSystemService(Context.NETWORK_SCORE_SERVICE); 73 if (scoreManager == null) 74 logDbg("Registered scoreManager NULL " + " service " + Context.NETWORK_SCORE_SERVICE); 75 else 76 logDbg("Registered scoreManager NOT NULL" + " service " + Context.NETWORK_SCORE_SERVICE); 77 78 if (scoreManager != null) { 79 // NETwork SCORE SERVICE doesnt seem to be working, so do nothing for now 80 mNetworkScoreCache = new WifiNetworkScoreCache(); 81 scoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache); 82 } else { 83 logDbg("No network score service: Couldnt register as a WiFi score Manager, type=" 84 + Integer.toString(NetworkKey.TYPE_WIFI) 85 + " service " + Context.NETWORK_SCORE_SERVICE); 86 mNetworkScoreCache = null; 87 } 88 } 89 90 int mScanResultMaximumAge = 30000; /* milliseconds unit */ 91 92 /* flush out scan results older than mScanResultMaximumAge */ 93 private void ageScanResultsOut(int delay) { 94 if (delay <= 0) { 95 delay = mScanResultMaximumAge; //something sane 96 } 97 Date now = new Date(); 98 long milli = now.getTime(); 99 if (VDBG) { 100 logDbg("ageScanResultsOut delay " + Integer.valueOf(delay) + " size " 101 + Integer.valueOf(scanResultCache.size()) + " now " + Long.valueOf(milli)); 102 } 103 104 Iterator<HashMap.Entry<String,ScanResult>> iter = scanResultCache.entrySet().iterator(); 105 while (iter.hasNext()) { 106 HashMap.Entry<String,ScanResult> entry = iter.next(); 107 ScanResult result = entry.getValue(); 108 109 if ((result.seen + delay) < milli) { 110 iter.remove(); 111 } 112 } 113 } 114 115 /* Check if this network is known to kepler and return its score */ 116 private int isScoredNetwork(ScanResult result) { 117 if (mNetworkScoreCache == null) 118 return 0; 119 return mNetworkScoreCache.getNetworkScore(result); 120 } 121 122 123 void addToScanCache(List<ScanResult> scanList) { 124 WifiConfiguration associatedConfig; 125 126 for(ScanResult result: scanList) { 127 result.seen = System.currentTimeMillis(); 128 129 ScanResult sr = scanResultCache.get(result.BSSID); 130 if (sr != null) { 131 // if there was a previous cache result for this BSSID, average the RSSI values 132 133 int previous_rssi = sr.level; 134 long previously_seen_milli = sr.seen; 135 136 /* average RSSI with previously seen instances of this scan result */ 137 int avg_rssi = result.level; 138 139 if ((previously_seen_milli > 0) 140 && (previously_seen_milli < mScanResultMaximumAge/2)) { 141 142 /* 143 * 144 * previously_seen_milli = 0 => RSSI = 0.5 * previous_seen_rssi + 0.5 * new_rssi 145 * 146 * If previously_seen_milli is 15+ seconds old: 147 * previously_seen_milli = 15000 => RSSI = new_rssi 148 * 149 */ 150 151 double alpha = 0.5 - (double)previously_seen_milli 152 / (double)mScanResultMaximumAge; 153 154 avg_rssi = (int)((double)avg_rssi * (1-alpha) + (double)previous_rssi * alpha); 155 156 } 157 result.level = avg_rssi; 158 159 //remove the previous Scan Result 160 scanResultCache.remove(result.BSSID); 161 } 162 163 scanResultCache.put(result.BSSID, new ScanResult(result)); 164 165 ScanResult srn = scanResultCache.get(result.BSSID); 166 167 //add this BSSID to the scanResultCache of the relevant WifiConfiguration 168 associatedConfig = mWifiConfigStore.updateSavedNetworkHistory(result); 169 170 //try to associate this BSSID to an existing Saved Wificonfiguration 171 if (associatedConfig == null) { 172 associatedConfig = mWifiConfigStore.associateWithConfiguration(result); 173 if (associatedConfig != null) { 174 if (VDBG) { 175 logDbg("addToScanCache save associated config " 176 + associatedConfig.SSID + " with " + associatedConfig.SSID); 177 } 178 mWifiStateMachine.sendMessage(WifiManager.SAVE_NETWORK, associatedConfig); 179 } 180 } 181 } 182 } 183 184 void logDbg(String message) { 185 long now = SystemClock.elapsedRealtimeNanos(); 186 String ts = String.format("[%,d us] ", now/1000); 187 Log.e(TAG, ts + message + " stack:" 188 + Thread.currentThread().getStackTrace()[2].getMethodName() +" - " 189 + Thread.currentThread().getStackTrace()[3].getMethodName() +" - " 190 + Thread.currentThread().getStackTrace()[4].getMethodName() +" - " 191 + Thread.currentThread().getStackTrace()[5].getMethodName()); 192 193 } 194 195 /* called directly from WifiStateMachine */ 196 void newSupplicantResults() { 197 List<ScanResult> scanList = mWifiStateMachine.syncGetScanResultsList(); 198 addToScanCache(scanList); 199 ageScanResultsOut(mScanResultMaximumAge); 200 if (DBG) 201 logDbg("newSupplicantResults size=" + Integer.valueOf(scanResultCache.size()) ); 202 203 attemptAutoJoin(); 204 mWifiConfigStore.writeKnownNetworkHistory(); 205 206 } 207 208 209 /* not used at the moment 210 * should be a call back from WifiScanner HAL ?? 211 * this function is not hooked and working yet, it will receive scan results from WifiScanners 212 * with the list of IEs,then populate the capabilities by parsing the IEs and inject the scan 213 * results as normal. 214 */ 215 void newHalScanResults() { 216 List<ScanResult> scanList = null;//mWifiScanner.syncGetScanResultsList(); 217 String akm = WifiParser.parse_akm(null, null); 218 logDbg(akm); 219 addToScanCache(scanList); 220 ageScanResultsOut(0); 221 attemptAutoJoin(); 222 mWifiConfigStore.writeKnownNetworkHistory(); 223 } 224 225 /* network link quality changed, called directly from WifiTrafficPoller, 226 or by listening to Link Quality intent */ 227 void linkQualitySignificantChange() { 228 attemptAutoJoin(); 229 } 230 231 /* 232 * compare a WifiConfiguration against the current network, return a delta score 233 * If not associated, and the candidate will always be better 234 * For instance if the candidate is a home network versus an unknown public wifi, 235 * the delta will be infinite, else compare Kepler scores etc… 236 ***/ 237 private int compareNetwork(WifiConfiguration candidate) { 238 WifiConfiguration currentNetwork = mWifiStateMachine.getCurrentWifiConfiguration(); 239 if (currentNetwork == null) 240 return 1000; 241 242 if (candidate.configKey(true).equals(currentNetwork.configKey(true))) { 243 return -1; 244 } 245 246 int order = compareWifiConfigurations(currentNetwork, candidate); 247 248 if (order > 0) { 249 //ascending: currentNetwork < candidate 250 return 10; //will try switch over to the candidate 251 } 252 253 return 0; 254 } 255 256 257 258 public void updateSavedConfigurationsPriorities(int netId) { 259 260 WifiConfiguration selected = mWifiConfigStore.getWifiConfiguration(netId); 261 if (selected == null) { 262 return; 263 } 264 265 // reenable autojoin for this network, 266 // since the user want to connect to this configuration 267 selected.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED; 268 269 if (DBG) { 270 if (selected.connectChoices != null) { 271 logDbg("updateSavedConfigurationsPriorities will update " 272 + Integer.toString(netId) + " now: " 273 + Integer.toString(selected.connectChoices.size())); 274 } else { 275 logDbg("updateSavedConfigurationsPriorities will update " 276 + Integer.toString(netId)); 277 } 278 } 279 280 List<WifiConfiguration> networks = mWifiConfigStore.getRecentConfiguredNetworks(12000, true); 281 if (networks == null) 282 return; 283 284 for (WifiConfiguration config: networks) { 285 286 if (DBG) 287 logDbg("updateSavedConfigurationsPriorities got " + config.SSID); 288 289 if (selected.configKey(true).equals(config.configKey(true))) { 290 continue; 291 } 292 293 //we were preferred over a recently seen config 294 if (selected.connectChoices == null) { 295 selected.connectChoices = new HashMap<String, Integer>(); 296 } 297 298 int rssi = WifiConfiguration.INVALID_RSSI; 299 if (config.visibility != null) { 300 rssi = config.visibility.rssi5; 301 if (config.visibility.rssi24 > rssi) 302 rssi = config.visibility.rssi24; 303 } 304 if (rssi < -80) { 305 continue; 306 } 307 308 //remember the user's choice: 309 //add the recently seen config to the selected's choice 310 logDbg("updateSavedConfigurationsPriorities add a choice " + selected.configKey(true) 311 + " over " + config.configKey(true) + " RSSI " + Integer.toString(rssi)); 312 selected.connectChoices.put(config.configKey(true), rssi); 313 314 if (config.connectChoices != null) { 315 if (VDBG) 316 logDbg("updateSavedConfigurationsPriorities try to remove " 317 + selected.configKey(true) + " from " + config.configKey(true)); 318 319 //remove the selected from the recently seen config's array 320 config.connectChoices.remove(selected.configKey(true)); 321 } 322 printChoices(config); 323 } 324 325 if (selected.connectChoices != null) { 326 if (VDBG) logDbg("updateSavedConfigurationsPriorities " + Integer.toString(netId) 327 + " now: " + Integer.toString(selected.connectChoices.size())); 328 } 329 330 mWifiConfigStore.writeKnownNetworkHistory(); 331 } 332 333 void printChoices(WifiConfiguration config) { 334 int num = 0; 335 if (config.connectChoices!= null) { 336 num = config.connectChoices.size(); 337 } 338 339 logDbg("printChoices " + config.SSID + " num choices: " + Integer.toString(num)); 340 if (config.connectChoices!= null) { 341 for (String key : config.connectChoices.keySet()) { 342 logDbg(" " + key); 343 } 344 } 345 } 346 347 348 boolean hasConnectChoice(WifiConfiguration source, WifiConfiguration target) { 349 boolean found = false; 350 if (source == null) 351 return false; 352 if (target == null) 353 return false; 354 355 if (source.connectChoices != null) { 356 if ( source.connectChoices.get(target.configKey(true)) != null) { 357 found = true; 358 } 359 } 360 361 if (source.linkedConfigurations != null) { 362 for (String key : source.linkedConfigurations.keySet()) { 363 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(key); 364 if (config != null) { 365 if (config.connectChoices != null) { 366 if (config.connectChoices.get(target.configKey(true)) != null) { 367 found = true; 368 } 369 } 370 } 371 } 372 } 373 return found; 374 } 375 376 int compareWifiConfigurationsRSSI(WifiConfiguration a, WifiConfiguration b) { 377 int order = 0; 378 int boost5 = 25; 379 380 WifiConfiguration.Visibility astatus = a.visibility; 381 WifiConfiguration.Visibility bstatus = b.visibility; 382 if (astatus == null || bstatus == null) { 383 //error 384 logDbg("compareWifiConfigurations NULL band status!"); 385 return 0; 386 } 387 if ((astatus.rssi5 > -70) && (bstatus.rssi5 == -127) 388 && ((astatus.rssi5+boost5) > (bstatus.rssi24))) { 389 //a is seen on 5GHz with good RSSI, greater rssi than b 390 //a is of higher priority - descending 391 order = -1; 392 } else if ((bstatus.rssi5 > -70) && (astatus.rssi5 == -127) 393 && ((bstatus.rssi5+boost5) > (bstatus.rssi24))) { 394 //b is seen on 5GHz with good RSSI, greater rssi than a 395 //a is of lower priority - ascending 396 order = 1; 397 } 398 return order; 399 } 400 401 int compareWifiConfigurations(WifiConfiguration a, WifiConfiguration b) { 402 int order = 0; 403 404 boolean linked = false; 405 406 if ((a.linkedConfigurations != null) && (b.linkedConfigurations != null)) { 407 if ((a.linkedConfigurations.get(b.configKey(true))!= null) 408 && (b.linkedConfigurations.get(a.configKey(true))!= null)) { 409 linked = true; 410 } 411 } 412 413 if (a.ephemeral && b.ephemeral == false) { 414 if (VDBG) { 415 logDbg("compareWifiConfigurations ephemeral and prefers " + b.SSID 416 + " over " + a.SSID); 417 } 418 return 1; //b is of higher priority - ascending 419 } 420 if (b.ephemeral && a.ephemeral == false) { 421 if (VDBG) { 422 logDbg("compareWifiConfigurations ephemeral and prefers " +a.SSID 423 + " over " + b.SSID); 424 } 425 return -1; //a is of higher priority - descending 426 } 427 428 int boost5 = 25; 429 if (linked) { 430 // then we try prefer 5GHz, and try to ignore user's choice 431 WifiConfiguration.Visibility astatus = a.visibility; 432 WifiConfiguration.Visibility bstatus = b.visibility; 433 if (astatus == null || bstatus == null) { 434 //error 435 logDbg("compareWifiConfigurations NULL band status!"); 436 return 0; 437 } 438 439 if (VDBG) { 440 logDbg("compareWifiConfigurations linked: " + Integer.toString(astatus.rssi5) 441 + "," + Integer.toString(astatus.rssi24) + " " 442 + Integer.toString(bstatus.rssi5) + "," 443 + Integer.toString(bstatus.rssi24)); 444 } 445 446 if ((astatus.rssi5 > -70) && (bstatus.rssi5 == -127) 447 && ((astatus.rssi5+boost5) > (bstatus.rssi24))) { 448 //a is seen on 5GHz with good RSSI, greater rssi than b 449 //a is of higher priority - descending 450 order = -10; 451 452 if (VDBG) { 453 logDbg("compareWifiConfigurations linked and prefers " + a.SSID 454 + " over " + b.SSID 455 + " due to 5GHz RSSI " + Integer.toString(astatus.rssi5) 456 + " over: 5=" + Integer.toString(bstatus.rssi5) 457 + ", 2.4=" + Integer.toString(bstatus.rssi5)); 458 } 459 } else if ((bstatus.rssi5 > -70) && (astatus.rssi5 == -127) 460 && ((bstatus.rssi5+boost5) > (bstatus.rssi24))) { 461 //b is seen on 5GHz with good RSSI, greater rssi than a 462 //a is of lower priority - ascending 463 if (VDBG) { 464 logDbg("compareWifiConfigurations linked and prefers " + b.SSID 465 + " over " + a.SSID + " due to 5GHz RSSI " 466 + Integer.toString(astatus.rssi5) + " over: 5=" 467 + Integer.toString(bstatus.rssi5) + ", 2.4=" 468 + Integer.toString(bstatus.rssi5)); 469 } 470 order = 10; 471 } 472 } 473 //assuming that the WifiConfiguration aren't part of the same "extended roam domain", 474 //then compare by user's choice. 475 if (hasConnectChoice(a, b)) { 476 //a is of higher priority - descending 477 order = order -2; 478 if (VDBG) { 479 logDbg("compareWifiConfigurations prefers -2 " + a.SSID 480 + " over " + b.SSID + " due to user choice order -> " + Integer.toString(order)); 481 } 482 } 483 484 if (hasConnectChoice(b, a)) { 485 //a is of lower priority - ascending 486 order = order + 2; 487 if (VDBG) { 488 logDbg("compareWifiConfigurations prefers +2 " + b.SSID + " over " 489 + a.SSID + " due to user choice order ->" + Integer.toString(order)); 490 } 491 } 492 493 if (order == 0) { 494 //we don't know anything - pick the last seen i.e. K behavior 495 //we should do this only for recently picked configurations 496 if (a.priority > b.priority) { 497 //a is of higher priority - descending 498 if (VDBG) { 499 logDbg("compareWifiConfigurations prefers -1 " + a.SSID + " over " 500 + b.SSID + " due to priority"); 501 } 502 503 order = -1; 504 } else if (a.priority < b.priority) { 505 //a is of lower priority - ascending 506 if (VDBG) { 507 logDbg("compareWifiConfigurations prefers +1 " + b.SSID + " over " 508 + a.SSID + " due to priority"); 509 } 510 511 order = 1; 512 } else { 513 //maybe just look at RSSI or band 514 if (VDBG) { 515 logDbg("compareWifiConfigurations prefers +1 " + b.SSID + " over " 516 + a.SSID + " due to nothing"); 517 } 518 519 order = compareWifiConfigurationsRSSI(a, b); //compare RSSI 520 } 521 } 522 523 String sorder = " == "; 524 if (order > 0) 525 sorder = " < "; 526 if (order < 0) 527 sorder = " > "; 528 529 if (VDBG) { 530 logDbg("compareWifiConfigurations Done: " + a.SSID + sorder 531 + b.SSID + " order " + Integer.toString(order)); 532 } 533 534 return order; 535 } 536 537 /* attemptAutoJoin function implement the core of the a network switching algorithm */ 538 void attemptAutoJoin() { 539 WifiConfiguration candidate = null; 540 541 /* obtain the subset of recently seen networks */ 542 List<WifiConfiguration> list = mWifiConfigStore.getRecentConfiguredNetworks(3000, true); 543 if (list == null) { 544 if (VDBG) logDbg("attemptAutoJoin nothing"); 545 return; 546 } 547 548 /* find the currently connected network: ask the supplicant directly */ 549 String val = mWifiNative.status(); 550 String status[] = val.split("\\r?\\n"); 551 if (VDBG) { 552 logDbg("attemptAutoJoin() status=" + val + " split=" 553 + Integer.toString(status.length)); 554 } 555 556 int currentNetId = -1; 557 for (String key : status) { 558 if (key.regionMatches(0, "id=", 0, 3)) { 559 int idx = 3; 560 currentNetId = 0; 561 while (idx < key.length()) { 562 char c = key.charAt(idx); 563 564 if ((c >= 0x30) && (c <= 0x39)) { 565 currentNetId *= 10; 566 currentNetId += c - 0x30; 567 idx++; 568 } else { 569 break; 570 } 571 } 572 } 573 } 574 logDbg("attemptAutoJoin() num recent config " + Integer.toString(list.size()) 575 + " ---> currentId=" + Integer.toString(currentNetId)); 576 577 /* select Best Network candidate from known WifiConfigurations */ 578 for (WifiConfiguration config : list) { 579 if ((config.status == WifiConfiguration.Status.DISABLED) 580 && (config.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE)) { 581 logDbg("attemptAutoJoin skip candidate due to auth failure " 582 + config.SSID + " key " + config.configKey(true)); 583 continue; 584 } 585 if (config.autoJoinStatus != WifiConfiguration.AUTO_JOIN_ENABLED) { 586 logDbg("attemptAutoJoin skip candidate due to auto join status " 587 + Integer.toString(config.autoJoinStatus) + " " + config.SSID + " key " 588 + config.configKey(true)); 589 continue; 590 } 591 592 if (config.networkId == currentNetId) { 593 logDbg("attemptAutoJoin skip current candidate " + Integer.toString(currentNetId) 594 + " key " + config.configKey(true)); 595 continue; 596 } 597 598 if (DBG) logDbg("attemptAutoJoin trying candidate id=" + config.networkId + " " 599 + config.SSID + " key " + config.configKey(true)); 600 601 if (candidate == null) { 602 candidate = config; 603 } else { 604 if (VDBG) { 605 logDbg("attemptAutoJoin will compare candidate " + candidate.SSID 606 + " with " + config.SSID + " key " + config.configKey(true)); 607 } 608 609 int order = compareWifiConfigurations(candidate, config); 610 611 if (VDBG) { 612 logDbg("attemptAutoJoin did compare candidate " + Integer.toString(order)); 613 } 614 615 if (order > 0) { 616 //ascending : candidate < config 617 candidate = config; 618 } 619 } 620 } 621 622 /* now, go thru scan result to try finding a better Herrevad network */ 623 if (mNetworkScoreCache != null) { 624 int rssi5 = WifiConfiguration.INVALID_RSSI; 625 int rssi24 = WifiConfiguration.INVALID_RSSI; 626 WifiConfiguration.Visibility visibility; 627 if (candidate != null) { 628 rssi5 = candidate.visibility.rssi5; 629 rssi24 = candidate.visibility.rssi24; 630 } 631 632 //get current date 633 Date now = new Date(); 634 long now_ms = now.getTime(); 635 636 if (rssi5 < -60 && rssi24 < -70) { 637 for (ScanResult result : scanResultCache.values()) { 638 if ((now_ms - result.seen) < 3000) { 639 int score = mNetworkScoreCache.getNetworkScore(result); 640 if (score > 0) { 641 // try any arbitrary formula for now, adding apple and oranges, 642 // i.e. adding network score and "dBm over noise" 643 if (result.frequency < 4000) { 644 if ((result.level + score) > (rssi24 -40)) { 645 // force it as open, TBD should we otherwise verify that this 646 // BSSID only supports open?? 647 result.capabilities = ""; 648 649 //switch to this scan result 650 candidate = 651 mWifiConfigStore.wifiConfigurationFromScanResult(result); 652 candidate.ephemeral = true; 653 } 654 } else { 655 if ((result.level + score) > (rssi5 -30)) { 656 // force it as open, TBD should we otherwise verify that this 657 // BSSID only supports open?? 658 result.capabilities = ""; 659 660 //switch to this scan result 661 candidate = 662 mWifiConfigStore.wifiConfigurationFromScanResult(result); 663 candidate.ephemeral = true; 664 } 665 } 666 } 667 } 668 } 669 } 670 } 671 672 if (candidate != null) { 673 /* if candidate is found, check the state of the connection so as 674 to decide if we should be acting on this candidate and switching over */ 675 if (VDBG) { 676 logDbg("attemptAutoJoin did find candidate " + candidate.SSID 677 + " key " + candidate.configKey(true)); 678 } 679 680 int networkDelta = compareNetwork(candidate); 681 if (networkDelta > 0) 682 logDbg("attemptAutoJoin did find candidate " + candidate.SSID 683 + " for delta " + Integer.toString(networkDelta)); 684 685 /* ASK traffic poller permission to switch: 686 for instance, 687 if user is currently streaming voice traffic, 688 then don’t switch regardless of the delta */ 689 690 if (mWifiTrafficPoller.shouldSwitchNetwork(networkDelta)) { 691 if (mStaStaSupported) { 692 693 } else { 694 if (DBG) { 695 logDbg("AutoJoin auto connect to netId " 696 + Integer.toString(candidate.networkId) 697 + " SSID " + candidate.SSID); 698 } 699 700 mWifiStateMachine.sendMessage(WifiStateMachine.CMD_AUTO_CONNECT, 701 candidate.networkId); 702 //mWifiConfigStore.enableNetworkWithoutBroadcast(candidate.networkId, true); 703 704 //we would do the below only if we want to persist the new choice 705 //mWifiConfigStore.selectNetwork(candidate.networkId); 706 707 } 708 } 709 } 710 if (VDBG) logDbg("Done attemptAutoJoin"); 711 } 712} 713 714