summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/wifi/AccessPointState.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/wifi/AccessPointState.java')
-rw-r--r--src/com/android/settings/wifi/AccessPointState.java869
1 files changed, 869 insertions, 0 deletions
diff --git a/src/com/android/settings/wifi/AccessPointState.java b/src/com/android/settings/wifi/AccessPointState.java
new file mode 100644
index 0000000..8dabbd1
--- /dev/null
+++ b/src/com/android/settings/wifi/AccessPointState.java
@@ -0,0 +1,869 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.net.NetworkInfo;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.GroupCipher;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiConfiguration.PairwiseCipher;
+import android.net.wifi.WifiConfiguration.Protocol;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+
+public final class AccessPointState implements Comparable<AccessPointState>, Parcelable {
+
+ private static final String TAG = "AccessPointState";
+
+ // Constants used for different security types
+ public static final String WPA2 = "WPA2";
+ public static final String WPA = "WPA";
+ public static final String WEP = "WEP";
+ public static final String OPEN = "Open";
+
+ /** String present in capabilities if the scan result is ad-hoc */
+ private static final String ADHOC_CAPABILITY = "[IBSS]";
+ /** String present in capabilities if the scan result is enterprise secured */
+ private static final String ENTERPRISE_CAPABILITY = "-EAP-";
+
+ // Localized strings for different security types
+ private static String LOCALIZED_WPA2;
+ private static String LOCALIZED_WPA;
+ private static String LOCALIZED_WEP;
+ private static String LOCALIZED_OPEN;
+ private static String LOCALIZED_UNKNOWN;
+ private static String LOCALIZED_VERBOSE_WPA2;
+ private static String LOCALIZED_VERBOSE_WPA;
+ private static String LOCALIZED_VERBOSE_WEP;
+ private static String LOCALIZED_VERBOSE_OPEN;
+
+
+ // Localized strings for various messages
+ private static String SUMMARY_NOT_IN_RANGE;
+ private static String SUMMARY_REMEMBERED;
+ private static String SUMMARY_CONNECTION_FAILED;
+
+ public static final String BSSID_ANY = "any";
+ public static final int NETWORK_ID_NOT_SET = -1;
+ /** This should be used with care! */
+ static final int NETWORK_ID_ANY = -2;
+
+ public static final int MATCH_NONE = 0;
+ public static final int MATCH_WEAK = 1;
+ public static final int MATCH_STRONG = 2;
+ public static final int MATCH_EXACT = 3;
+
+ // Don't set these directly, use the setters.
+ public int networkId;
+ public int priority;
+ public boolean hiddenSsid;
+ public int linkSpeed;
+ public int ipAddress;
+ public String bssid;
+ public String ssid;
+ public int signal;
+ public boolean primary;
+ public boolean seen;
+ public boolean configured;
+ public NetworkInfo.DetailedState status;
+ public String security;
+ public boolean disabled;
+
+ /**
+ * Use this for sorting based on signal strength. It is a heavily-damped
+ * time-averaged weighted signal.
+ */
+ private float signalForSorting = Float.MIN_VALUE;
+
+ private static final float DAMPING_FACTOR = 0.2f;
+
+ /**
+ * This will be a user entered password, and NOT taken from wpa_supplicant
+ * (since it would give us *)
+ */
+ private String mPassword;
+ private boolean mConfigHadPassword;
+
+ public static final int WEP_PASSWORD_AUTO = 0;
+ public static final int WEP_PASSWORD_ASCII = 1;
+ public static final int WEP_PASSWORD_HEX = 2;
+ private int mWepPasswordType;
+
+ private Context mContext;
+
+ /**
+ * If > 0, don't refresh (changes are being batched), use
+ * {@link #blockRefresh()} and {@link #unblockRefresh()} only.
+ */
+ private int mBlockRefresh;
+ /**
+ * This will be set by {@link #requestRefresh} and shouldn't be written to
+ * elsewhere.
+ */
+ private boolean mNeedsRefresh;
+
+ private AccessPointStateCallback mCallback;
+
+ private StringBuilder mSummaryBuilder = new StringBuilder();
+
+ interface AccessPointStateCallback {
+ void refreshAccessPointState();
+ }
+
+ public AccessPointState(Context context) {
+ this();
+
+ setContext(context);
+ }
+
+ private AccessPointState() {
+ bssid = BSSID_ANY;
+ ssid = "";
+ networkId = NETWORK_ID_NOT_SET;
+ hiddenSsid = false;
+ }
+
+ void setContext(Context context) {
+ mContext = context;
+ setStrings();
+ }
+
+ private void setStrings() {
+ final Context c = mContext;
+
+ if (SUMMARY_NOT_IN_RANGE == null && c != null) {
+ SUMMARY_NOT_IN_RANGE = c.getString(R.string.summary_not_in_range);
+ SUMMARY_REMEMBERED = c.getString(R.string.summary_remembered);
+ SUMMARY_CONNECTION_FAILED = c.getString(R.string.summary_connection_failed);
+
+ LOCALIZED_OPEN = c.getString(R.string.wifi_security_open);
+ LOCALIZED_WEP = c.getString(R.string.wifi_security_wep);
+ LOCALIZED_WPA = c.getString(R.string.wifi_security_wpa);
+ LOCALIZED_WPA2 = c.getString(R.string.wifi_security_wpa2);
+
+ LOCALIZED_VERBOSE_OPEN = c.getString(R.string.wifi_security_verbose_open);
+ LOCALIZED_VERBOSE_WEP = c.getString(R.string.wifi_security_verbose_wep);
+ LOCALIZED_VERBOSE_WPA = c.getString(R.string.wifi_security_verbose_wpa);
+ LOCALIZED_VERBOSE_WPA2 = c.getString(R.string.wifi_security_verbose_wpa2);
+
+ LOCALIZED_UNKNOWN = c.getString(R.string.wifi_security_unknown);
+ }
+ }
+
+ public void setNetworkId(int networkId) {
+ this.networkId = networkId;
+ }
+
+ public void setBssid(String bssid) {
+ if (bssid != null) {
+ // If the BSSID is a wildcard, do NOT let a specific BSSID replace it
+ if (!this.bssid.equals(BSSID_ANY)) {
+ this.bssid = bssid;
+ }
+ }
+ }
+
+ private String getWpaSupplicantBssid() {
+ return bssid.equals(BSSID_ANY) ? null : bssid;
+ }
+
+ public static String convertToQuotedString(String string) {
+ if (TextUtils.isEmpty(string)) {
+ return "";
+ }
+
+ final int lastPos = string.length() - 1;
+ if (lastPos < 0 || (string.charAt(0) == '"' && string.charAt(lastPos) == '"')) {
+ return string;
+ }
+
+ return "\"" + string + "\"";
+ }
+
+ public void setPrimary(boolean primary) {
+ if (this.primary != primary) {
+ this.primary = primary;
+ requestRefresh();
+ }
+ }
+
+ public void setSeen(boolean seen) {
+ if (this.seen != seen) {
+ this.seen = seen;
+ requestRefresh();
+ }
+ }
+
+ public void setDisabled(boolean disabled) {
+ if (this.disabled != disabled) {
+ this.disabled = disabled;
+ requestRefresh();
+ }
+ }
+
+ public void setSignal(int signal) {
+
+ if (signalForSorting == Float.MIN_VALUE) {
+ signalForSorting = signal;
+ } else {
+ signalForSorting = (DAMPING_FACTOR * signal) + ((1-DAMPING_FACTOR) * signalForSorting);
+ }
+
+ if (this.signal != signal) {
+ this.signal = signal;
+ requestRefresh();
+ }
+ }
+
+ public String getHumanReadableSsid() {
+ if (TextUtils.isEmpty(ssid)) {
+ return "";
+ }
+
+ final int lastPos = ssid.length() - 1;
+ if (ssid.charAt(0) == '"' && ssid.charAt(lastPos) == '"') {
+ return ssid.substring(1, lastPos);
+ }
+
+ return ssid;
+ }
+
+ public void setSsid(String ssid) {
+ if (ssid != null) {
+ this.ssid = convertToQuotedString(ssid);
+ requestRefresh();
+ }
+ }
+
+ public void setPriority(int priority) {
+ if (this.priority != priority) {
+ this.priority = priority;
+ requestRefresh();
+ }
+ }
+
+ public void setHiddenSsid(boolean hiddenSsid) {
+ if (this.hiddenSsid != hiddenSsid) {
+ this.hiddenSsid = hiddenSsid;
+ requestRefresh();
+ }
+ }
+
+ public void setLinkSpeed(int linkSpeed) {
+ if (this.linkSpeed != linkSpeed) {
+ this.linkSpeed = linkSpeed;
+ requestRefresh();
+ }
+ }
+
+ public void setIpAddress(int address) {
+ if (ipAddress != address) {
+ ipAddress = address;
+ requestRefresh();
+ }
+ }
+
+ public void setConfigured(boolean configured) {
+ if (this.configured != configured) {
+ this.configured = configured;
+ requestRefresh();
+ }
+ }
+
+ public void setStatus(NetworkInfo.DetailedState status) {
+ if (this.status != status) {
+ this.status = status;
+ requestRefresh();
+ }
+ }
+
+ public void setSecurity(String security) {
+ if (TextUtils.isEmpty(this.security) || !this.security.equals(security)) {
+ this.security = security;
+ requestRefresh();
+ }
+ }
+
+ public boolean hasSecurity() {
+ return security != null && !security.contains(OPEN);
+ }
+
+ public String getHumanReadableSecurity() {
+ if (security.equals(OPEN)) return LOCALIZED_OPEN;
+ else if (security.equals(WEP)) return LOCALIZED_WEP;
+ else if (security.equals(WPA)) return LOCALIZED_WPA;
+ else if (security.equals(WPA2)) return LOCALIZED_WPA2;
+
+ return LOCALIZED_UNKNOWN;
+ }
+
+ public void updateFromScanResult(ScanResult scanResult) {
+ blockRefresh();
+
+ // We don't keep specific AP BSSIDs and instead leave that as wildcard
+
+ setSeen(true);
+ setSsid(scanResult.SSID);
+ if (networkId == NETWORK_ID_NOT_SET) {
+ // Since ScanResults don't cross-reference network ID, we set it as a wildcard
+ setNetworkId(NETWORK_ID_ANY);
+ }
+ setSignal(scanResult.level);
+ setSecurity(getScanResultSecurity(scanResult));
+ unblockRefresh();
+ }
+
+ /**
+ * @return The security of a given {@link ScanResult}.
+ */
+ public static String getScanResultSecurity(ScanResult scanResult) {
+ final String cap = scanResult.capabilities;
+ final String[] securityModes = { WEP, WPA, WPA2 };
+ for (int i = securityModes.length - 1; i >= 0; i--) {
+ if (cap.contains(securityModes[i])) {
+ return securityModes[i];
+ }
+ }
+
+ return OPEN;
+ }
+
+ /**
+ * @return Whether the given ScanResult represents an adhoc network.
+ */
+ public static boolean isAdhoc(ScanResult scanResult) {
+ return scanResult.capabilities.contains(ADHOC_CAPABILITY);
+ }
+
+ /**
+ * @return Whether the given ScanResult has enterprise security.
+ */
+ public static boolean isEnterprise(ScanResult scanResult) {
+ return scanResult.capabilities.contains(ENTERPRISE_CAPABILITY);
+ }
+
+ public void updateFromWifiConfiguration(WifiConfiguration wifiConfig) {
+ if (wifiConfig != null) {
+ blockRefresh();
+ setBssid(wifiConfig.BSSID);
+ setNetworkId(wifiConfig.networkId);
+ setPriority(wifiConfig.priority);
+ setHiddenSsid(wifiConfig.hiddenSSID);
+ setSsid(wifiConfig.SSID);
+ setConfigured(true);
+ setDisabled(wifiConfig.status == WifiConfiguration.Status.DISABLED);
+ parseWifiConfigurationSecurity(wifiConfig);
+ unblockRefresh();
+ }
+ }
+
+ public void setPassword(String password) {
+ setPassword(password, WEP_PASSWORD_AUTO);
+ }
+
+ public void setPassword(String password, int wepPasswordType) {
+ mPassword = password;
+ mWepPasswordType = wepPasswordType;
+ }
+
+ public boolean hasPassword() {
+ return !TextUtils.isEmpty(mPassword) || mConfigHadPassword;
+ }
+
+ private static boolean hasPassword(WifiConfiguration wifiConfig) {
+ return !TextUtils.isEmpty(wifiConfig.preSharedKey)
+ || !TextUtils.isEmpty(wifiConfig.wepKeys[0])
+ || !TextUtils.isEmpty(wifiConfig.wepKeys[1])
+ || !TextUtils.isEmpty(wifiConfig.wepKeys[2])
+ || !TextUtils.isEmpty(wifiConfig.wepKeys[3]);
+ }
+
+ private void parseWifiConfigurationSecurity(WifiConfiguration wifiConfig) {
+ setSecurity(getWifiConfigurationSecurity(wifiConfig));
+ mConfigHadPassword = hasPassword(wifiConfig);
+ }
+
+ /**
+ * @return The security of a given {@link WifiConfiguration}.
+ */
+ public static String getWifiConfigurationSecurity(WifiConfiguration wifiConfig) {
+
+ if (wifiConfig.allowedKeyManagement.get(KeyMgmt.NONE)) {
+ // If we never set group ciphers, wpa_supplicant puts all of them.
+ // For open, we don't set group ciphers.
+ // For WEP, we specifically only set WEP40 and WEP104, so CCMP
+ // and TKIP should not be there.
+ if (!wifiConfig.allowedGroupCiphers.get(GroupCipher.CCMP)
+ && (wifiConfig.allowedGroupCiphers.get(GroupCipher.WEP40)
+ || wifiConfig.allowedGroupCiphers.get(GroupCipher.WEP104))) {
+ return WEP;
+ } else {
+ return OPEN;
+ }
+ } else if (wifiConfig.allowedProtocols.get(Protocol.RSN)) {
+ return WPA2;
+ } else if (wifiConfig.allowedProtocols.get(Protocol.WPA)) {
+ return WPA;
+ } else {
+ Log.w(TAG, "Unknown security type from WifiConfiguration, falling back on open.");
+ return OPEN;
+ }
+ }
+
+ public void updateFromWifiInfo(WifiInfo wifiInfo, NetworkInfo.DetailedState state) {
+ if (wifiInfo != null) {
+ blockRefresh();
+ setBssid(wifiInfo.getBSSID());
+ setLinkSpeed(wifiInfo.getLinkSpeed());
+ setNetworkId(wifiInfo.getNetworkId());
+ setIpAddress(wifiInfo.getIpAddress());
+ setSsid(wifiInfo.getSSID());
+ if (state != null) {
+ setStatus(state);
+ }
+ setHiddenSsid(wifiInfo.getHiddenSSID());
+ unblockRefresh();
+ }
+ }
+
+ /**
+ * @return Whether this AP can be connected to at the moment.
+ */
+ public boolean isConnectable() {
+ return !primary && seen;
+ }
+
+ /**
+ * @return Whether this AP can be forgotten at the moment.
+ */
+ public boolean isForgetable() {
+ return configured;
+ }
+
+ /**
+ * Updates the state as if it were never configured.
+ * <p>
+ * Note: This will not pass the forget call to the Wi-Fi API.
+ */
+ public void forget() {
+ blockRefresh();
+ setConfigured(false);
+ setNetworkId(NETWORK_ID_NOT_SET);
+ setPrimary(false);
+ setStatus(null);
+ setDisabled(false);
+ unblockRefresh();
+ }
+
+ public void updateWifiConfiguration(WifiConfiguration config) {
+ config.BSSID = getWpaSupplicantBssid();
+ config.priority = priority;
+ config.hiddenSSID = hiddenSsid;
+ config.SSID = convertToQuotedString(ssid);
+
+ setupSecurity(config);
+ }
+
+ private void setupSecurity(WifiConfiguration config) {
+ config.allowedAuthAlgorithms.clear();
+ config.allowedGroupCiphers.clear();
+ config.allowedKeyManagement.clear();
+ config.allowedPairwiseCiphers.clear();
+ config.allowedProtocols.clear();
+
+ if (TextUtils.isEmpty(security)) {
+ security = OPEN;
+ Log.w(TAG, "Empty security, assuming open");
+ }
+
+ if (security.equals(WEP)) {
+
+ // If password is empty, it should be left untouched
+ if (!TextUtils.isEmpty(mPassword)) {
+ if (mWepPasswordType == WEP_PASSWORD_AUTO) {
+ if (isHexWepKey(mPassword)) {
+ config.wepKeys[0] = mPassword;
+ } else {
+ config.wepKeys[0] = convertToQuotedString(mPassword);
+ }
+ } else {
+ config.wepKeys[0] = mWepPasswordType == WEP_PASSWORD_ASCII
+ ? convertToQuotedString(mPassword)
+ : mPassword;
+ }
+ }
+
+ config.wepTxKeyIndex = 0;
+
+ config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+ config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+
+ config.allowedGroupCiphers.set(GroupCipher.WEP40);
+ config.allowedGroupCiphers.set(GroupCipher.WEP104);
+
+ } else if (security.equals(WPA) || security.equals(WPA2)){
+ config.allowedGroupCiphers.set(GroupCipher.TKIP);
+ config.allowedGroupCiphers.set(GroupCipher.CCMP);
+
+ config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+
+ config.allowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+ config.allowedPairwiseCiphers.set(PairwiseCipher.TKIP);
+
+ config.allowedProtocols.set(security.equals(WPA2) ? Protocol.RSN : Protocol.WPA);
+
+ // If password is empty, it should be left untouched
+ if (!TextUtils.isEmpty(mPassword)) {
+ config.preSharedKey = convertToQuotedString(mPassword);
+ }
+
+ } else if (security.equals(OPEN)) {
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ }
+ }
+
+ private static boolean isHexWepKey(String wepKey) {
+ final int len = wepKey.length();
+
+ // WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
+ if (len != 10 && len != 26 && len != 58) {
+ return false;
+ }
+
+ for (int i = len - 1; i >= 0; i--) {
+ final char c = wepKey.charAt(i);
+ if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f')) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void setCallback(AccessPointStateCallback callback) {
+ mCallback = callback;
+ }
+
+ void blockRefresh() {
+ mBlockRefresh++;
+ }
+
+ void unblockRefresh() {
+ if (--mBlockRefresh == 0 && mNeedsRefresh) {
+ requestRefresh();
+ }
+ }
+
+ private void requestRefresh() {
+ if (mBlockRefresh > 0) {
+ mNeedsRefresh = true;
+ return;
+ }
+
+ if (mCallback != null) {
+ mCallback.refreshAccessPointState();
+ }
+
+ mNeedsRefresh = false;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see #hashCode()
+ * @see #equals(Object)
+ */
+ public int matches(int otherNetworkId, String otherBssid, String otherSsid,
+ String otherSecurity) {
+
+ // Whenever this method is touched, please ensure #equals and #hashCode
+ // still work with the changes here!
+
+ if (otherSsid == null) {
+ if (WifiLayer.LOGV) {
+ Log.w(TAG, "BSSID: " + otherBssid + ", SSID: " + otherSsid);
+ }
+ return MATCH_NONE;
+ }
+
+ /*
+ * If we both have 'security' set, it must match (an open network still
+ * has 'security' set to OPEN)
+ */
+ if (security != null && otherSecurity != null) {
+ if (!security.equals(otherSecurity)) {
+ return MATCH_NONE;
+ }
+ }
+
+ // WifiConfiguration gives an empty bssid as a BSSID wildcard
+ if (TextUtils.isEmpty(otherBssid)) {
+ otherBssid = AccessPointState.BSSID_ANY;
+ }
+
+ final boolean networkIdMatches = networkId == otherNetworkId;
+ if (!networkIdMatches && networkId != NETWORK_ID_ANY && otherNetworkId != NETWORK_ID_ANY) {
+ // Network IDs don't match (e.g., 1 & 2 or unset & 1) and neither is a wildcard
+ return MATCH_NONE;
+ }
+
+ if (networkIdMatches && otherNetworkId != NETWORK_ID_NOT_SET
+ && otherNetworkId != NETWORK_ID_ANY) {
+ // Network ID matches (they're set to the same ID)
+ return MATCH_EXACT;
+ }
+
+ // So now, network IDs aren't set or at least one is a wildcard
+
+ final boolean bssidMatches = bssid.equals(otherBssid);
+ final boolean otherBssidIsWildcard = otherBssid.equals(BSSID_ANY);
+ if (bssidMatches && !otherBssidIsWildcard) {
+ // BSSID matches (and neither is a wildcard)
+ return MATCH_STRONG;
+ }
+
+ if (!bssidMatches && !bssid.equals(BSSID_ANY) && !otherBssidIsWildcard) {
+ // BSSIDs don't match (e.g., 00:24:21:21:42:12 & 42:12:44:21:22:52)
+ // and neither is a wildcard
+ return MATCH_NONE;
+ }
+
+ // So now, BSSIDs are both wildcards
+
+ final boolean ssidMatches = ssid.equals(otherSsid);
+ if (ssidMatches) {
+ // SSID matches
+ return MATCH_WEAK;
+ }
+
+ return MATCH_NONE;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see #matches(int, String, String)
+ * @see #equals(Object)
+ */
+ @Override
+ public int hashCode() {
+ // Two equal() objects must have same hashCode.
+ // With Wi-Fi, the broadest match is if two SSIDs are the same. The finer-grained matches
+ // imply this (for example, the same network IDs means the same WifiConfiguration which
+ // means the same SSID).
+ // See #matches for the exact matching algorithm we use.
+ return ssid != null ? ssid.hashCode() : 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see #matches(int, String, String)
+ * @see #hashCode()
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!o.getClass().equals(getClass())) {
+ return false;
+ }
+
+ final AccessPointState other = (AccessPointState) o;
+
+ // To see which conditions cause two AccessPointStates to be equal, see
+ // where #matches returns MATCH_WEAK or greater.
+
+ return matches(other.networkId, other.bssid, other.ssid, other.security) >= MATCH_WEAK;
+ }
+
+ public int matchesWifiConfiguration(WifiConfiguration wifiConfig) {
+ String security = getWifiConfigurationSecurity(wifiConfig);
+ return matches(wifiConfig.networkId, wifiConfig.BSSID, wifiConfig.SSID, security);
+ }
+
+ String getSummarizedStatus() {
+ StringBuilder sb = mSummaryBuilder;
+ sb.delete(0, sb.length());
+
+ if (primary && status != null) {
+ buildSummary(sb, WifiStatus.getPrintable(mContext, status), true);
+
+ } else if (!seen) {
+ buildSummary(sb, SUMMARY_NOT_IN_RANGE, true);
+
+ // Remembered comes second in this case
+ if (!primary && configured) {
+ buildSummary(sb, SUMMARY_REMEMBERED, true);
+ }
+
+ } else {
+ if (configured && disabled) {
+ // The connection failure overrides all in this case
+ return SUMMARY_CONNECTION_FAILED;
+ }
+
+ // Remembered comes first in this case
+ if (!primary && configured) {
+ buildSummary(sb, SUMMARY_REMEMBERED, true);
+ }
+
+ // If it is seen (and not the primary), show the security type
+ String verboseSecurity = getVerboseSecurity();
+ if (verboseSecurity != null) {
+ buildSummary(sb, verboseSecurity, true);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private String getVerboseSecurity() {
+ if (WEP.equals(security)) {
+ return LOCALIZED_VERBOSE_WEP;
+ } else if (WPA.equals(security)) {
+ return LOCALIZED_VERBOSE_WPA;
+ } else if (WPA2.equals(security)) {
+ return LOCALIZED_VERBOSE_WPA2;
+ } else if (OPEN.equals(security)) {
+ return LOCALIZED_VERBOSE_OPEN;
+ } else {
+ return null;
+ }
+ }
+
+ private void buildSummary(StringBuilder sb, String string, boolean autoLowerCaseFirstLetter) {
+ if (sb.length() == 0) {
+ sb.append(string);
+ } else {
+ sb.append(", ");
+ if (autoLowerCaseFirstLetter) {
+ // Convert first letter to lowercase
+ sb.append(Character.toLowerCase(string.charAt(0))).append(string, 1,
+ string.length());
+ } else {
+ sb.append(string);
+ }
+ }
+ }
+
+ public int compareTo(AccessPointState other) {
+ // This ranks the states for displaying in the AP list, not for
+ // connecting to (wpa_supplicant does that using the WifiConfiguration's
+ // priority field).
+
+ // Clarity > efficiency, of this logic:
+ int comparison;
+
+ // Primary
+ comparison = (other.primary ? 1 : 0) - (primary ? 1 : 0);
+ if (comparison != 0) return comparison;
+
+ // Currently seen (similar to, but not always the same as within range)
+ comparison = (other.seen ? 1 : 0) - (seen ? 1 : 0);
+ if (comparison != 0) return comparison;
+
+ // Configured
+ comparison = (other.configured ? 1 : 0) - (configured ? 1 : 0);
+ if (comparison != 0) return comparison;
+
+ if (!configured) {
+ // Neither are configured
+
+ // Open network
+ comparison = (hasSecurity() ? 1 : 0) - (other.hasSecurity() ? 1 : 0);
+ if (comparison != 0) return comparison;
+ }
+
+ // Signal strength
+ comparison = (int) (other.signalForSorting - signalForSorting);
+ if (comparison != 0) return comparison;
+
+ // Alphabetical
+ return ssid.compareToIgnoreCase(other.ssid);
+ }
+
+ public String toString() {
+ return ssid + " (" + bssid + ", " + networkId + ", " + super.toString() + ")";
+ }
+
+ /** Implement the Parcelable interface */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(bssid);
+ dest.writeInt(configured ? 1 : 0);
+ dest.writeInt(ipAddress);
+ dest.writeInt(linkSpeed);
+ dest.writeInt(networkId);
+ dest.writeInt(primary ? 1 : 0);
+ dest.writeInt(priority);
+ dest.writeInt(hiddenSsid ? 1 : 0);
+ dest.writeString(security);
+ dest.writeInt(seen ? 1 : 0);
+ dest.writeInt(disabled ? 1 : 0);
+ dest.writeInt(signal);
+ dest.writeString(ssid);
+ dest.writeString(status != null ? status.toString() : null);
+ dest.writeString(mPassword);
+ dest.writeInt(mConfigHadPassword ? 1 : 0);
+ dest.writeInt(mWepPasswordType);
+ }
+
+ /** Implement the Parcelable interface */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Creator<AccessPointState> CREATOR =
+ new Creator<AccessPointState>() {
+ public AccessPointState createFromParcel(Parcel in) {
+ AccessPointState state = new AccessPointState();
+ state.bssid = in.readString();
+ state.configured = in.readInt() == 1;
+ state.ipAddress = in.readInt();
+ state.linkSpeed = in.readInt();
+ state.networkId = in.readInt();
+ state.primary = in.readInt() == 1;
+ state.priority = in.readInt();
+ state.hiddenSsid = in.readInt() == 1;
+ state.security = in.readString();
+ state.seen = in.readInt() == 1;
+ state.disabled = in.readInt() == 1;
+ state.signal = in.readInt();
+ state.ssid = in.readString();
+ String statusStr = in.readString();
+ if (statusStr != null) {
+ state.status = NetworkInfo.DetailedState.valueOf(statusStr);
+ }
+ state.mPassword = in.readString();
+ state.mConfigHadPassword = in.readInt() == 1;
+ state.mWepPasswordType = in.readInt();
+ return state;
+ }
+
+ public AccessPointState[] newArray(int size) {
+ return new AccessPointState[size];
+ }
+ };
+
+
+}