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 17 package com.android.settings.wifi; 18 19 import com.android.settings.R; 20 21 import android.content.Context; 22 import android.graphics.drawable.Drawable; 23 import android.graphics.drawable.StateListDrawable; 24 import android.net.NetworkInfo; 25 import android.net.NetworkInfo.DetailedState; 26 import android.net.NetworkInfo.State; 27 import android.net.wifi.ScanResult; 28 import android.net.wifi.WifiConfiguration; 29 import android.net.wifi.WifiConfiguration.KeyMgmt; 30 import android.net.wifi.WifiInfo; 31 import android.net.wifi.WifiManager; 32 import android.os.Bundle; 33 import android.preference.Preference; 34 import android.util.Log; 35 import android.util.LruCache; 36 import android.view.View; 37 import android.widget.ImageView; 38 import android.widget.TextView; 39 40 import java.util.Map; 41 42 43 class AccessPoint extends Preference { 44 static final String TAG = "Settings.AccessPoint"; 45 46 /** 47 * Lower bound on the 2.4 GHz (802.11b/g/n) WLAN channels 48 */ 49 public static final int LOWER_FREQ_24GHZ = 2400; 50 51 /** 52 * Upper bound on the 2.4 GHz (802.11b/g/n) WLAN channels 53 */ 54 public static final int HIGHER_FREQ_24GHZ = 2500; 55 56 /** 57 * Lower bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels 58 */ 59 public static final int LOWER_FREQ_5GHZ = 4900; 60 61 /** 62 * Upper bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels 63 */ 64 public static final int HIGHER_FREQ_5GHZ = 5900; 65 66 /** 67 * Experimental: we should be able to show the user the list of BSSIDs and bands 68 * for that SSID. 69 * For now this data is used only with Verbose Logging so as to show the band and number 70 * of BSSIDs on which that network is seen. 71 */ 72 public LruCache<String, ScanResult> mScanResultCache; 73 74 75 private static final String KEY_NETWORKINFO = "key_networkinfo"; 76 private static final String KEY_WIFIINFO = "key_wifiinfo"; 77 private static final String KEY_SCANRESULT = "key_scanresult"; 78 private static final String KEY_CONFIG = "key_config"; 79 80 private static final int[] STATE_SECURED = { 81 R.attr.state_encrypted 82 }; 83 private static final int[] STATE_NONE = {}; 84 85 private static int[] wifi_signal_attributes = { R.attr.wifi_signal }; 86 87 /** 88 * These values are matched in string arrays -- changes must be kept in sync 89 */ 90 static final int SECURITY_NONE = 0; 91 static final int SECURITY_WEP = 1; 92 static final int SECURITY_PSK = 2; 93 static final int SECURITY_EAP = 3; 94 95 enum PskType { 96 UNKNOWN, 97 WPA, 98 WPA2, 99 WPA_WPA2 100 } 101 102 String ssid; 103 String bssid; 104 int security; 105 int networkId = -1; 106 boolean wpsAvailable = false; 107 boolean showSummary = true; 108 109 PskType pskType = PskType.UNKNOWN; 110 111 private WifiConfiguration mConfig; 112 /* package */ScanResult mScanResult; 113 114 private int mRssi = Integer.MAX_VALUE; 115 private long mSeen = 0; 116 117 private WifiInfo mInfo; 118 private NetworkInfo mNetworkInfo; 119 private TextView mSummaryView; 120 121 private static final int VISIBILITY_MAX_AGE_IN_MILLI = 1000000; 122 private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000; 123 private static final int SECOND_TO_MILLI = 1000; 124 125 static int getSecurity(WifiConfiguration config) { 126 if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { 127 return SECURITY_PSK; 128 } 129 if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || 130 config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { 131 return SECURITY_EAP; 132 } 133 return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE; 134 } 135 136 private static int getSecurity(ScanResult result) { 137 if (result.capabilities.contains("WEP")) { 138 return SECURITY_WEP; 139 } else if (result.capabilities.contains("PSK")) { 140 return SECURITY_PSK; 141 } else if (result.capabilities.contains("EAP")) { 142 return SECURITY_EAP; 143 } 144 return SECURITY_NONE; 145 } 146 147 public String getSecurityString(boolean concise) { 148 Context context = getContext(); 149 switch(security) { 150 case SECURITY_EAP: 151 return concise ? context.getString(R.string.wifi_security_short_eap) : 152 context.getString(R.string.wifi_security_eap); 153 case SECURITY_PSK: 154 switch (pskType) { 155 case WPA: 156 return concise ? context.getString(R.string.wifi_security_short_wpa) : 157 context.getString(R.string.wifi_security_wpa); 158 case WPA2: 159 return concise ? context.getString(R.string.wifi_security_short_wpa2) : 160 context.getString(R.string.wifi_security_wpa2); 161 case WPA_WPA2: 162 return concise ? context.getString(R.string.wifi_security_short_wpa_wpa2) : 163 context.getString(R.string.wifi_security_wpa_wpa2); 164 case UNKNOWN: 165 default: 166 return concise ? context.getString(R.string.wifi_security_short_psk_generic) 167 : context.getString(R.string.wifi_security_psk_generic); 168 } 169 case SECURITY_WEP: 170 return concise ? context.getString(R.string.wifi_security_short_wep) : 171 context.getString(R.string.wifi_security_wep); 172 case SECURITY_NONE: 173 default: 174 return concise ? "" : context.getString(R.string.wifi_security_none); 175 } 176 } 177 178 private static PskType getPskType(ScanResult result) { 179 boolean wpa = result.capabilities.contains("WPA-PSK"); 180 boolean wpa2 = result.capabilities.contains("WPA2-PSK"); 181 if (wpa2 && wpa) { 182 return PskType.WPA_WPA2; 183 } else if (wpa2) { 184 return PskType.WPA2; 185 } else if (wpa) { 186 return PskType.WPA; 187 } else { 188 Log.w(TAG, "Received abnormal flag string: " + result.capabilities); 189 return PskType.UNKNOWN; 190 } 191 } 192 193 AccessPoint(Context context, WifiConfiguration config) { 194 super(context); 195 loadConfig(config); 196 refresh(); 197 } 198 199 AccessPoint(Context context, ScanResult result) { 200 super(context); 201 loadResult(result); 202 refresh(); 203 } 204 205 AccessPoint(Context context, Bundle savedState) { 206 super(context); 207 208 mConfig = savedState.getParcelable(KEY_CONFIG); 209 if (mConfig != null) { 210 loadConfig(mConfig); 211 } 212 mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT); 213 if (mScanResult != null) { 214 loadResult(mScanResult); 215 } 216 mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO); 217 if (savedState.containsKey(KEY_NETWORKINFO)) { 218 mNetworkInfo = savedState.getParcelable(KEY_NETWORKINFO); 219 } 220 update(mInfo, mNetworkInfo); 221 } 222 223 public void saveWifiState(Bundle savedState) { 224 savedState.putParcelable(KEY_CONFIG, mConfig); 225 savedState.putParcelable(KEY_SCANRESULT, mScanResult); 226 savedState.putParcelable(KEY_WIFIINFO, mInfo); 227 if (mNetworkInfo != null) { 228 savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo); 229 } 230 } 231 232 private void loadConfig(WifiConfiguration config) { 233 ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID)); 234 bssid = config.BSSID; 235 security = getSecurity(config); 236 networkId = config.networkId; 237 mConfig = config; 238 } 239 240 private void loadResult(ScanResult result) { 241 ssid = result.SSID; 242 bssid = result.BSSID; 243 security = getSecurity(result); 244 wpsAvailable = security != SECURITY_EAP && result.capabilities.contains("WPS"); 245 if (security == SECURITY_PSK) 246 pskType = getPskType(result); 247 mRssi = result.level; 248 mScanResult = result; 249 if (result.seen > mSeen) { 250 mSeen = result.seen; 251 } 252 } 253 254 @Override 255 protected void onBindView(View view) { 256 super.onBindView(view); 257 updateIcon(getLevel(), getContext()); 258 259 mSummaryView = (TextView) view.findViewById(com.android.internal.R.id.summary); 260 mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); 261 262 notifyChanged(); 263 } 264 265 protected void updateIcon(int level, Context context) { 266 if (level == -1) { 267 setIcon(null); 268 } else { 269 Drawable drawable = getIcon(); 270 271 if (drawable == null) { 272 // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then 273 // set the icon (drawable) to that state's drawable. 274 StateListDrawable sld = (StateListDrawable) context.getTheme() 275 .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0); 276 // If sld is null then we are indexing and therefore do not have access to 277 // (nor need to display) the drawable. 278 if (sld != null) { 279 sld.setState((security != SECURITY_NONE) ? STATE_SECURED : STATE_NONE); 280 drawable = sld.getCurrent(); 281 setIcon(drawable); 282 } 283 } 284 285 if (drawable != null) { 286 drawable.setLevel(level); 287 } 288 } 289 } 290 291 @Override 292 public int compareTo(Preference preference) { 293 if (!(preference instanceof AccessPoint)) { 294 return 1; 295 } 296 AccessPoint other = (AccessPoint) preference; 297 // Active one goes first. 298 if (isActive() && !other.isActive()) return -1; 299 if (!isActive() && other.isActive()) return 1; 300 301 // Reachable one goes before unreachable one. 302 if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1; 303 if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1; 304 305 // Configured one goes before unconfigured one. 306 if (networkId != WifiConfiguration.INVALID_NETWORK_ID 307 && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1; 308 if (networkId == WifiConfiguration.INVALID_NETWORK_ID 309 && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1; 310 311 // Sort by signal strength. 312 int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi); 313 if (difference != 0) { 314 return difference; 315 } 316 // Sort by ssid. 317 return ssid.compareToIgnoreCase(other.ssid); 318 } 319 320 @Override 321 public boolean equals(Object other) { 322 if (!(other instanceof AccessPoint)) return false; 323 return (this.compareTo((AccessPoint) other) == 0); 324 } 325 326 @Override 327 public int hashCode() { 328 int result = 0; 329 if (mInfo != null) result += 13 * mInfo.hashCode(); 330 result += 19 * mRssi; 331 result += 23 * networkId; 332 result += 29 * ssid.hashCode(); 333 return result; 334 } 335 336 boolean update(ScanResult result) { 337 if (result.seen > mSeen) { 338 mSeen = result.seen; 339 } 340 if (WifiSettings.mVerboseLogging > 0) { 341 if (mScanResultCache == null) { 342 mScanResultCache = new LruCache<String, ScanResult>(32); 343 } 344 mScanResultCache.put(result.BSSID, result); 345 } 346 347 if (ssid.equals(result.SSID) && security == getSecurity(result)) { 348 if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) { 349 int oldLevel = getLevel(); 350 mRssi = result.level; 351 if (getLevel() != oldLevel) { 352 notifyChanged(); 353 } 354 } 355 // This flag only comes from scans, is not easily saved in config 356 if (security == SECURITY_PSK) { 357 pskType = getPskType(result); 358 } 359 mScanResult = result; 360 refresh(); 361 return true; 362 } 363 return false; 364 } 365 366 /** Return whether the given {@link WifiInfo} is for this access point. */ 367 private boolean isInfoForThisAccessPoint(WifiInfo info) { 368 if (networkId != WifiConfiguration.INVALID_NETWORK_ID) { 369 return networkId == info.getNetworkId(); 370 } else { 371 // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID. 372 // (Note that we only do this if the WifiConfiguration explicitly equals INVALID). 373 // TODO: Handle hex string SSIDs. 374 return ssid.equals(removeDoubleQuotes(info.getSSID())); 375 } 376 } 377 378 void update(WifiInfo info, NetworkInfo networkInfo) { 379 boolean reorder = false; 380 if (info != null && isInfoForThisAccessPoint(info)) { 381 reorder = (mInfo == null); 382 mRssi = info.getRssi(); 383 mInfo = info; 384 mNetworkInfo = networkInfo; 385 refresh(); 386 } else if (mInfo != null) { 387 reorder = true; 388 mInfo = null; 389 mNetworkInfo = null; 390 refresh(); 391 } 392 if (reorder) { 393 notifyHierarchyChanged(); 394 } 395 } 396 397 int getLevel() { 398 if (mRssi == Integer.MAX_VALUE) { 399 return -1; 400 } 401 return WifiManager.calculateSignalLevel(mRssi, 4); 402 } 403 404 WifiConfiguration getConfig() { 405 return mConfig; 406 } 407 408 WifiInfo getInfo() { 409 return mInfo; 410 } 411 412 NetworkInfo getNetworkInfo() { 413 return mNetworkInfo; 414 } 415 416 DetailedState getState() { 417 return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null; 418 } 419 420 static String removeDoubleQuotes(String string) { 421 int length = string.length(); 422 if ((length > 1) && (string.charAt(0) == '"') 423 && (string.charAt(length - 1) == '"')) { 424 return string.substring(1, length - 1); 425 } 426 return string; 427 } 428 429 static String convertToQuotedString(String string) { 430 return "\"" + string + "\""; 431 } 432 433 /** 434 * Shows or Hides the Summary of an AccessPoint. 435 * 436 * @param showSummary true will show the summary, false will hide the summary 437 */ 438 public void setShowSummary(boolean showSummary) { 439 this.showSummary = showSummary; 440 if (mSummaryView != null) { 441 mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE); 442 } // otherwise, will be handled in onBindView. 443 } 444 445 /** 446 * Returns the visibility status of the WifiConfiguration. 447 * 448 * @return autojoin debugging information 449 * TODO: use a string formatter 450 * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"] 451 * For instance [-40,5/-30,2] 452 */ 453 private String getVisibilityStatus() { 454 StringBuilder visibility = new StringBuilder(); 455 StringBuilder scans24GHz = null; 456 StringBuilder scans5GHz = null; 457 String bssid = null; 458 459 long now = System.currentTimeMillis(); 460 461 if (mInfo != null) { 462 bssid = mInfo.getBSSID(); 463 if (bssid != null) { 464 visibility.append(" ").append(bssid); 465 } 466 visibility.append(" rssi=").append(mInfo.getRssi()); 467 visibility.append(" "); 468 visibility.append(" score=").append(mInfo.score); 469 visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate)); 470 visibility.append(String.format("%.1f,", mInfo.txRetriesRate)); 471 visibility.append(String.format("%.1f ", mInfo.txBadRate)); 472 visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate)); 473 } 474 475 if (mScanResultCache != null) { 476 int rssi5 = WifiConfiguration.INVALID_RSSI; 477 int rssi24 = WifiConfiguration.INVALID_RSSI; 478 int num5 = 0; 479 int num24 = 0; 480 int numBlackListed = 0; 481 int n24 = 0; // Number scan results we included in the string 482 int n5 = 0; // Number scan results we included in the string 483 Map<String, ScanResult> list = mScanResultCache.snapshot(); 484 // TODO: sort list by RSSI or age 485 for (ScanResult result : list.values()) { 486 if (result.seen == 0) 487 continue; 488 489 if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++; 490 491 if (result.frequency >= LOWER_FREQ_5GHZ 492 && result.frequency <= HIGHER_FREQ_5GHZ) { 493 // Strictly speaking: [4915, 5825] 494 // number of known BSSID on 5GHz band 495 num5 = num5 + 1; 496 } else if (result.frequency >= LOWER_FREQ_24GHZ 497 && result.frequency <= HIGHER_FREQ_24GHZ) { 498 // Strictly speaking: [2412, 2482] 499 // number of known BSSID on 2.4Ghz band 500 num24 = num24 + 1; 501 } 502 503 // Ignore results seen, older than 20 seconds 504 if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue; 505 506 if (result.frequency >= LOWER_FREQ_5GHZ 507 && result.frequency <= HIGHER_FREQ_5GHZ) { 508 if (result.level > rssi5) { 509 rssi5 = result.level; 510 } 511 if (n5 < 4) { 512 if (scans5GHz == null) scans5GHz = new StringBuilder(); 513 scans5GHz.append(" \n{").append(result.BSSID); 514 if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*"); 515 scans5GHz.append("=").append(result.frequency); 516 scans5GHz.append(",").append(result.level); 517 if (result.autoJoinStatus != 0) { 518 scans5GHz.append(",st=").append(result.autoJoinStatus); 519 } 520 if (result.numIpConfigFailures != 0) { 521 scans5GHz.append(",ipf=").append(result.numIpConfigFailures); 522 } 523 scans5GHz.append("}"); 524 n5++; 525 } 526 } else if (result.frequency >= LOWER_FREQ_24GHZ 527 && result.frequency <= HIGHER_FREQ_24GHZ) { 528 if (result.level > rssi24) { 529 rssi24 = result.level; 530 } 531 if (n24 < 4) { 532 if (scans24GHz == null) scans24GHz = new StringBuilder(); 533 scans24GHz.append(" \n{").append(result.BSSID); 534 if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*"); 535 scans24GHz.append("=").append(result.frequency); 536 scans24GHz.append(",").append(result.level); 537 if (result.autoJoinStatus != 0) { 538 scans24GHz.append(",st=").append(result.autoJoinStatus); 539 } 540 if (result.numIpConfigFailures != 0) { 541 scans24GHz.append(",ipf=").append(result.numIpConfigFailures); 542 } 543 scans24GHz.append("}"); 544 n24++; 545 } 546 } 547 } 548 visibility.append(" ["); 549 if (num24 > 0) { 550 visibility.append("(").append(num24).append(")"); 551 if (n24 <= 4) { 552 if (scans24GHz != null) { 553 visibility.append(scans24GHz.toString()); 554 } 555 } else { 556 visibility.append("max=").append(rssi24); 557 if (scans24GHz != null) { 558 visibility.append(",").append(scans24GHz.toString()); 559 } 560 } 561 } 562 visibility.append(";"); 563 if (num5 > 0) { 564 visibility.append("(").append(num5).append(")"); 565 if (n5 <= 4) { 566 if (scans5GHz != null) { 567 visibility.append(scans5GHz.toString()); 568 } 569 } else { 570 visibility.append("max=").append(rssi5); 571 if (scans5GHz != null) { 572 visibility.append(",").append(scans5GHz.toString()); 573 } 574 } 575 } 576 if (numBlackListed > 0) 577 visibility.append("!").append(numBlackListed); 578 visibility.append("]"); 579 } else { 580 if (mRssi != Integer.MAX_VALUE) { 581 visibility.append(" rssi="); 582 visibility.append(mRssi); 583 if (mScanResult != null) { 584 visibility.append(", f="); 585 visibility.append(mScanResult.frequency); 586 } 587 } 588 } 589 590 return visibility.toString(); 591 } 592 593 /** 594 * Return whether this is the active connection. 595 * For ephemeral connections (networkId is invalid), this returns false if the network is 596 * disconnected. 597 */ 598 boolean isActive() { 599 return mNetworkInfo != null && 600 (networkId != WifiConfiguration.INVALID_NETWORK_ID || 601 mNetworkInfo.getState() != State.DISCONNECTED); 602 } 603 604 /** 605 * Updates the title and summary; may indirectly call notifyChanged(). 606 */ 607 private void refresh() { 608 setTitle(ssid); 609 610 final Context context = getContext(); 611 updateIcon(getLevel(), context); 612 613 // Force new summary 614 setSummary(null); 615 616 // Update to new summary 617 StringBuilder summary = new StringBuilder(); 618 619 if (isActive()) { // This is the active connection 620 summary.append(Summary.get(context, getState(), 621 networkId == WifiConfiguration.INVALID_NETWORK_ID)); 622 } else if (mConfig != null 623 && mConfig.hasNoInternetAccess()) { 624 summary.append(context.getString(R.string.wifi_no_internet)); 625 } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED && 626 mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON) 627 || mConfig.autoJoinStatus 628 >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) { 629 if (mConfig.autoJoinStatus 630 >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) { 631 if (mConfig.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE) { 632 summary.append(context.getString(R.string.wifi_disabled_network_failure)); 633 } else if (mConfig.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE) { 634 summary.append(context.getString(R.string.wifi_disabled_password_failure)); 635 } else { 636 summary.append(context.getString(R.string.wifi_disabled_wifi_failure)); 637 } 638 } else { 639 switch (mConfig.disableReason) { 640 case WifiConfiguration.DISABLED_AUTH_FAILURE: 641 summary.append(context.getString(R.string.wifi_disabled_password_failure)); 642 break; 643 case WifiConfiguration.DISABLED_DHCP_FAILURE: 644 case WifiConfiguration.DISABLED_DNS_FAILURE: 645 summary.append(context.getString(R.string.wifi_disabled_network_failure)); 646 break; 647 case WifiConfiguration.DISABLED_UNKNOWN_REASON: 648 case WifiConfiguration.DISABLED_ASSOCIATION_REJECT: 649 summary.append(context.getString(R.string.wifi_disabled_generic)); 650 break; 651 } 652 } 653 } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range 654 summary.append(context.getString(R.string.wifi_not_in_range)); 655 } else { // In range, not disabled. 656 if (mConfig != null) { // Is saved network 657 summary.append(context.getString(R.string.wifi_remembered)); 658 } 659 } 660 661 if (WifiSettings.mVerboseLogging > 0) { 662 // Add RSSI/band information for this config, what was seen up to 6 seconds ago 663 // verbose WiFi Logging is only turned on thru developers settings 664 if (mInfo != null && mNetworkInfo != null) { // This is the active connection 665 summary.append(" f=" + Integer.toString(mInfo.getFrequency())); 666 } 667 summary.append(" " + getVisibilityStatus()); 668 if (mConfig != null && mConfig.autoJoinStatus > 0) { 669 summary.append(" (" + mConfig.autoJoinStatus); 670 if (mConfig.blackListTimestamp > 0) { 671 long now = System.currentTimeMillis(); 672 long diff = (now - mConfig.blackListTimestamp)/1000; 673 long sec = diff%60; //seconds 674 long min = (diff/60)%60; //minutes 675 long hour = (min/60)%60; //hours 676 summary.append(", "); 677 if (hour > 0) summary.append(Long.toString(hour) + "h "); 678 summary.append( Long.toString(min) + "m "); 679 summary.append( Long.toString(sec) + "s "); 680 } 681 summary.append(")"); 682 } 683 if (mConfig != null && mConfig.numIpConfigFailures > 0) { 684 summary.append(" ipf=").append(mConfig.numIpConfigFailures); 685 } 686 if (mConfig != null && mConfig.numConnectionFailures > 0) { 687 summary.append(" cf=").append(mConfig.numConnectionFailures); 688 } 689 if (mConfig != null && mConfig.numAuthFailures > 0) { 690 summary.append(" authf=").append(mConfig.numAuthFailures); 691 } 692 if (mConfig != null && mConfig.numNoInternetAccessReports > 0) { 693 summary.append(" noInt=").append(mConfig.numNoInternetAccessReports); 694 } 695 } 696 697 if (summary.length() > 0) { 698 setSummary(summary.toString()); 699 setShowSummary(true); 700 } else { 701 setShowSummary(false); 702 } 703 } 704 705 /** 706 * Generate and save a default wifiConfiguration with common values. 707 * Can only be called for unsecured networks. 708 * @hide 709 */ 710 protected void generateOpenNetworkConfig() { 711 if (security != SECURITY_NONE) 712 throw new IllegalStateException(); 713 if (mConfig != null) 714 return; 715 mConfig = new WifiConfiguration(); 716 mConfig.SSID = AccessPoint.convertToQuotedString(ssid); 717 mConfig.allowedKeyManagement.set(KeyMgmt.NONE); 718 } 719 } 720