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;
     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