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