Move some wifi tracking code to SettingsLib

Move tracking of which networks are available/saved and their state
over to SettingsLib to share it with Quick Settings.

Bug: 19180466
Change-Id: Iaeef06b26da8cb38e1ba09a7d105d04d499dc181
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0496036..82c9a67 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1317,8 +1317,6 @@
 
     <!-- Wifi Assistant title.  [CHAR LIMIT=40] -->
     <string name="wifi_assistant_title">Wi\u2011Fi Assistant</string>
-    <!-- Status message of Wi-Fi when it is connected by a Wi-Fi assistant application. [CHAR LIMIT=NONE] -->
-    <string name="connected_via_wfa">Connected via Wi\u2011Fi assistant</string>
 
     <!-- Wifi Display settings. The title of the screen. [CHAR LIMIT=40] -->
     <string name="wifi_display_settings_title">Cast screen</string>
@@ -1422,8 +1420,6 @@
     <string name="wifi_error">Error</string>
     <!-- Toast message when Wi-Fi or bluetooth is disallowed in airplane mode -->
     <string name="wifi_in_airplane_mode">In Airplane mode</string>
-    <!-- Toast message when Wi-Fi cannot scan for networks -->
-    <string name="wifi_fail_to_scan">Can\'t scan for networks</string>
     <!-- Checkbox title for option to notify user when open networks are nearby -->
     <string name="wifi_notify_open_networks">Network notification</string>
     <!-- Checkbox summary for option to notify user when open networks are nearby [CHAR LIMIT=60]-->
@@ -1578,21 +1574,6 @@
     <string name="wifi_unchanged">(unchanged)</string>
     <!-- Hint for unspecified fields -->
     <string name="wifi_unspecified">(unspecified)</string>
-    <!-- Summary for the remembered network. -->
-    <string name="wifi_remembered">Saved</string>
-    <!-- Status for networks disabled for unknown reason -->
-    <string name="wifi_disabled_generic">Disabled</string>
-    <!-- Status for networked disabled from a DNS or DHCP failure -->
-    <string name="wifi_disabled_network_failure">IP Configuration Failure</string>
-    <!-- Status for networked disabled from a wifi association failure -->
-    <string name="wifi_disabled_wifi_failure">WiFi Connection Failure</string>
-    <!-- Status for networks disabled from authentication failure (wrong password
-         or certificate). -->
-    <string name="wifi_disabled_password_failure">Authentication problem</string>
-    <!-- Summary for the remembered network but currently not in range. -->
-    <string name="wifi_not_in_range">Not in range</string>
-    <!-- Summary for the remembered network but no internet connection was detected. -->
-    <string name="wifi_no_internet">No Internet Access Detected, won\'t automatically reconnect.</string>
     <!-- Substring of status line when Wi-Fi Protected Setup (WPS) is available and
          string is listed first [CHAR LIMIT=20]-->
     <string name="wifi_wps_available_first_item">WPS available</string>
@@ -1602,35 +1583,6 @@
     <!-- Message in WriteWifiConfigToNfcDialog when prompted to enter network password [CHAR_LIMIT=40] -->
     <string name="wifi_wps_nfc_enter_password">Enter your network password</string>
 
-    <!-- Do not translate.  Concise terminology for wifi with WEP security -->
-    <string name="wifi_security_short_wep">WEP</string>
-    <!-- Do not translate.  Concise terminology for wifi with WPA security -->
-    <string name="wifi_security_short_wpa">WPA</string>
-    <!-- Do not translate.  Concise terminology for wifi with WPA2 security -->
-    <string name="wifi_security_short_wpa2">WPA2</string>
-    <!-- Do not translate.  Concise terminology for wifi with both WPA/WPA2 security -->
-    <string name="wifi_security_short_wpa_wpa2">WPA/WPA2</string>
-    <!-- Do not translate.  Concise terminology for wifi with unknown PSK type -->
-    <string name="wifi_security_short_psk_generic">@string/wifi_security_short_wpa_wpa2</string>
-    <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP security -->
-    <string name="wifi_security_short_eap">802.1x</string>
-
-    <!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. -->
-    <string name="wifi_security_none">None</string>
-
-    <!-- Do not translate.  Terminology for wifi with WEP security -->
-    <string name="wifi_security_wep">WEP</string>
-    <!-- Do not translate.  Terminology for wifi with WPA security -->
-    <string name="wifi_security_wpa">WPA PSK</string>
-    <!-- Do not translate.  Terminology for wifi with WPA2 security -->
-    <string name="wifi_security_wpa2">WPA2 PSK</string>
-    <!-- Do not translate.  Terminology for wifi with both WPA/WPA2 security, or unknown -->
-    <string name="wifi_security_wpa_wpa2">WPA/WPA2 PSK</string>
-    <!-- Do not translate.  Terminology for wifi with unknown PSK type -->
-    <string name="wifi_security_psk_generic">@string/wifi_security_wpa_wpa2</string>
-    <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP security -->
-    <string name="wifi_security_eap">802.1x EAP</string>
-
     <string name="wifi_scan_always_turnon_message">To improve location accuracy and for other purposes, <xliff:g id="app_name">%1$s</xliff:g> wants to turn on network scanning, even when Wi-Fi is off.\n\nAllow this for all apps that want to scan?</string>
     <!-- Message informing the user how to turn off  [CHAR LIMIT=200] -->
     <string name="wifi_scan_always_turnoff_message">To turn this off, go to Advanced in the overflow menu.</string>
diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java
index 5b8ad0d..06648db 100644
--- a/src/com/android/settings/AirplaneModeEnabler.java
+++ b/src/com/android/settings/AirplaneModeEnabler.java
@@ -29,6 +29,7 @@
 
 import com.android.internal.telephony.PhoneStateIntentReceiver;
 import com.android.internal.telephony.TelephonyProperties;
+import com.android.settingslib.WirelessUtils;
 
 public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListener {
 
@@ -71,7 +72,7 @@
 
     public void resume() {
         
-        mSwitchPref.setChecked(isAirplaneModeOn(mContext));
+        mSwitchPref.setChecked(WirelessUtils.isAirplaneModeOn(mContext));
 
         mPhoneStateReceiver.registerIntent();
         mSwitchPref.setOnPreferenceChangeListener(this);
@@ -86,11 +87,6 @@
         mContext.getContentResolver().unregisterContentObserver(mAirplaneModeObserver);
     }
 
-    public static boolean isAirplaneModeOn(Context context) {
-        return Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
-    }
-
     private void setAirplaneModeOn(boolean enabling) {
         // Change the system setting
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 
@@ -113,7 +109,7 @@
      * - mobile does not send failure notification, fail on timeout.
      */
     private void onAirplaneModeChanged() {
-        mSwitchPref.setChecked(isAirplaneModeOn(mContext));
+        mSwitchPref.setChecked(WirelessUtils.isAirplaneModeOn(mContext));
     }
     
     /**
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index e9c39d9..0bd6b29 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -230,16 +230,6 @@
         Log.d(TAG, s);
     }
 
-    public static boolean isRadioAllowed(Context context, String type) {
-        if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
-            return true;
-        }
-        // Here we use the same logic in onCreate().
-        String toggleable = Settings.Global.getString(context.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
-        return toggleable != null && toggleable.contains(type);
-    }
-
     private boolean isSmsSupported() {
         // Some tablet has sim card but could not do telephony operations. Skip those.
         return mTm.isSmsCapable();
diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java
index b006c65..188a37a 100644
--- a/src/com/android/settings/bluetooth/BluetoothEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java
@@ -24,14 +24,13 @@
 import android.os.Handler;
 import android.os.Message;
 import android.provider.Settings;
-import android.widget.CompoundButton;
 import android.widget.Switch;
 import android.widget.Toast;
 
 import com.android.settings.R;
-import com.android.settings.WirelessSettings;
 import com.android.settings.search.Index;
 import com.android.settings.widget.SwitchBar;
+import com.android.settingslib.WirelessUtils;
 
 /**
  * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox
@@ -177,7 +176,7 @@
     public void onSwitchChanged(Switch switchView, boolean isChecked) {
         // Show toast message if Bluetooth is not allowed in airplane mode
         if (isChecked &&
-                !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
+                !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
             Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
             // Reset switch to off
             switchView.setChecked(false);
diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java
deleted file mode 100644
index 9c72bbc..0000000
--- a/src/com/android/settings/wifi/AccessPoint.java
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
- * Copyright (C) 2010 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.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.util.Log;
-import android.util.LruCache;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.Map;
-
-
-class AccessPoint extends Preference {
-    static final String TAG = "Settings.AccessPoint";
-
-    /**
-     * Lower bound on the 2.4 GHz (802.11b/g/n) WLAN channels
-     */
-    public static final int LOWER_FREQ_24GHZ = 2400;
-
-    /**
-     * Upper bound on the 2.4 GHz (802.11b/g/n) WLAN channels
-     */
-    public static final int HIGHER_FREQ_24GHZ = 2500;
-
-    /**
-     * Lower bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels
-     */
-    public static final int LOWER_FREQ_5GHZ = 4900;
-
-    /**
-     * Upper bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels
-     */
-    public static final int HIGHER_FREQ_5GHZ = 5900;
-
-    /**
-     * Experimental: we should be able to show the user the list of BSSIDs and bands
-     *  for that SSID.
-     *  For now this data is used only with Verbose Logging so as to show the band and number
-     *  of BSSIDs on which that network is seen.
-     */
-    public LruCache<String, ScanResult> mScanResultCache;
-
-
-    private static final String KEY_NETWORKINFO = "key_networkinfo";
-    private static final String KEY_WIFIINFO = "key_wifiinfo";
-    private static final String KEY_SCANRESULT = "key_scanresult";
-    private static final String KEY_CONFIG = "key_config";
-
-    private static final int[] STATE_SECURED = {
-        R.attr.state_encrypted
-    };
-    private static final int[] STATE_NONE = {};
-
-    private static int[] wifi_signal_attributes = { R.attr.wifi_signal };
-
-    /**
-     * These values are matched in string arrays -- changes must be kept in sync
-     */
-    static final int SECURITY_NONE = 0;
-    static final int SECURITY_WEP = 1;
-    static final int SECURITY_PSK = 2;
-    static final int SECURITY_EAP = 3;
-
-    enum PskType {
-        UNKNOWN,
-        WPA,
-        WPA2,
-        WPA_WPA2
-    }
-
-    String ssid;
-    String bssid;
-    int security;
-    int networkId = -1;
-    boolean wpsAvailable = false;
-    boolean showSummary = true;
-
-    PskType pskType = PskType.UNKNOWN;
-
-    private WifiConfiguration mConfig;
-    /* package */ScanResult mScanResult;
-
-    private int mRssi = Integer.MAX_VALUE;
-    private long mSeen = 0;
-
-    private WifiInfo mInfo;
-    private NetworkInfo mNetworkInfo;
-    private TextView mSummaryView;
-
-    private static final int VISIBILITY_MAX_AGE_IN_MILLI = 1000000;
-    private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000;
-    private static final int SECOND_TO_MILLI = 1000;
-
-    static int getSecurity(WifiConfiguration config) {
-        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
-            return SECURITY_PSK;
-        }
-        if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
-                config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
-            return SECURITY_EAP;
-        }
-        return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
-    }
-
-    private static int getSecurity(ScanResult result) {
-        if (result.capabilities.contains("WEP")) {
-            return SECURITY_WEP;
-        } else if (result.capabilities.contains("PSK")) {
-            return SECURITY_PSK;
-        } else if (result.capabilities.contains("EAP")) {
-            return SECURITY_EAP;
-        }
-        return SECURITY_NONE;
-    }
-
-    public String getSecurityString(boolean concise) {
-        Context context = getContext();
-        switch(security) {
-            case SECURITY_EAP:
-                return concise ? context.getString(R.string.wifi_security_short_eap) :
-                    context.getString(R.string.wifi_security_eap);
-            case SECURITY_PSK:
-                switch (pskType) {
-                    case WPA:
-                        return concise ? context.getString(R.string.wifi_security_short_wpa) :
-                            context.getString(R.string.wifi_security_wpa);
-                    case WPA2:
-                        return concise ? context.getString(R.string.wifi_security_short_wpa2) :
-                            context.getString(R.string.wifi_security_wpa2);
-                    case WPA_WPA2:
-                        return concise ? context.getString(R.string.wifi_security_short_wpa_wpa2) :
-                            context.getString(R.string.wifi_security_wpa_wpa2);
-                    case UNKNOWN:
-                    default:
-                        return concise ? context.getString(R.string.wifi_security_short_psk_generic)
-                                : context.getString(R.string.wifi_security_psk_generic);
-                }
-            case SECURITY_WEP:
-                return concise ? context.getString(R.string.wifi_security_short_wep) :
-                    context.getString(R.string.wifi_security_wep);
-            case SECURITY_NONE:
-            default:
-                return concise ? "" : context.getString(R.string.wifi_security_none);
-        }
-    }
-
-    private static PskType getPskType(ScanResult result) {
-        boolean wpa = result.capabilities.contains("WPA-PSK");
-        boolean wpa2 = result.capabilities.contains("WPA2-PSK");
-        if (wpa2 && wpa) {
-            return PskType.WPA_WPA2;
-        } else if (wpa2) {
-            return PskType.WPA2;
-        } else if (wpa) {
-            return PskType.WPA;
-        } else {
-            Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
-            return PskType.UNKNOWN;
-        }
-    }
-
-    AccessPoint(Context context, WifiConfiguration config) {
-        super(context);
-        loadConfig(config);
-        refresh();
-    }
-
-    AccessPoint(Context context, ScanResult result) {
-        super(context);
-        loadResult(result);
-        refresh();
-    }
-
-    AccessPoint(Context context, Bundle savedState) {
-        super(context);
-
-        mConfig = savedState.getParcelable(KEY_CONFIG);
-        if (mConfig != null) {
-            loadConfig(mConfig);
-        }
-        mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT);
-        if (mScanResult != null) {
-            loadResult(mScanResult);
-        }
-        mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO);
-        if (savedState.containsKey(KEY_NETWORKINFO)) {
-            mNetworkInfo = savedState.getParcelable(KEY_NETWORKINFO);
-        }
-        update(mInfo, mNetworkInfo);
-    }
-
-    public void saveWifiState(Bundle savedState) {
-        savedState.putParcelable(KEY_CONFIG, mConfig);
-        savedState.putParcelable(KEY_SCANRESULT, mScanResult);
-        savedState.putParcelable(KEY_WIFIINFO, mInfo);
-        if (mNetworkInfo != null) {
-            savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo);
-        }
-    }
-
-    private void loadConfig(WifiConfiguration config) {
-        ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
-        bssid = config.BSSID;
-        security = getSecurity(config);
-        networkId = config.networkId;
-        mConfig = config;
-    }
-
-    private void loadResult(ScanResult result) {
-        ssid = result.SSID;
-        bssid = result.BSSID;
-        security = getSecurity(result);
-        wpsAvailable = security != SECURITY_EAP && result.capabilities.contains("WPS");
-        if (security == SECURITY_PSK)
-            pskType = getPskType(result);
-        mRssi = result.level;
-        mScanResult = result;
-        if (result.seen > mSeen) {
-            mSeen = result.seen;
-        }
-    }
-
-    @Override
-    protected void onBindView(View view) {
-        super.onBindView(view);
-        updateIcon(getLevel(), getContext());
-
-        mSummaryView = (TextView) view.findViewById(com.android.internal.R.id.summary);
-        mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE);
-
-        notifyChanged();
-    }
-
-    protected void updateIcon(int level, Context context) {
-        if (level == -1) {
-            setIcon(null);
-        } else {
-            Drawable drawable = getIcon();
-
-            if (drawable == null) {
-                // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
-                // set the icon (drawable) to that state's drawable.
-                StateListDrawable sld = (StateListDrawable) context.getTheme()
-                        .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
-                // If sld is null then we are indexing and therefore do not have access to
-                // (nor need to display) the drawable.
-                if (sld != null) {
-                    sld.setState((security != SECURITY_NONE) ? STATE_SECURED : STATE_NONE);
-                    drawable = sld.getCurrent();
-                    setIcon(drawable);
-                }
-            }
-
-            if (drawable != null) {
-                drawable.setLevel(level);
-            }
-        }
-    }
-
-    public void showAppIcon() {
-        PackageManager pm = getContext().getPackageManager();
-        String systemName = pm.getNameForUid(android.os.Process.SYSTEM_UID);
-
-        Drawable drawable = pm.getDefaultActivityIcon();
-        if (mConfig == null) {
-            drawable.setAlpha(0);
-        } else if (mConfig.creatorName.equals(systemName)) {
-            drawable = getContext().getApplicationInfo().loadIcon(pm);
-        } else {
-            try {
-                drawable = pm.getApplicationIcon(mConfig.creatorName);
-            } catch (NameNotFoundException nnfe) {
-                // use default app icon
-            }
-        }
-
-        setIcon(drawable);
-    }
-
-    @Override
-    public int compareTo(Preference preference) {
-        if (!(preference instanceof AccessPoint)) {
-            return 1;
-        }
-        AccessPoint other = (AccessPoint) preference;
-        // Active one goes first.
-        if (isActive() && !other.isActive()) return -1;
-        if (!isActive() && other.isActive()) return 1;
-
-        // Reachable one goes before unreachable one.
-        if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
-        if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
-
-        // Configured one goes before unconfigured one.
-        if (networkId != WifiConfiguration.INVALID_NETWORK_ID
-                && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
-        if (networkId == WifiConfiguration.INVALID_NETWORK_ID
-                && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
-
-        // Sort by signal strength.
-        int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
-        if (difference != 0) {
-            return difference;
-        }
-        // Sort by ssid.
-        return ssid.compareToIgnoreCase(other.ssid);
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof AccessPoint)) return false;
-        return (this.compareTo((AccessPoint) other) == 0);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 0;
-        if (mInfo != null) result += 13 * mInfo.hashCode();
-        result += 19 * mRssi;
-        result += 23 * networkId;
-        result += 29 * ssid.hashCode();
-        return result;
-    }
-
-    boolean update(ScanResult result) {
-        if (result.seen > mSeen) {
-            mSeen = result.seen;
-        }
-        if (WifiSettings.mVerboseLogging > 0) {
-            if (mScanResultCache == null) {
-                mScanResultCache = new LruCache<String, ScanResult>(32);
-            }
-            mScanResultCache.put(result.BSSID, result);
-        }
-
-        if (ssid.equals(result.SSID) && security == getSecurity(result)) {
-            if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
-                int oldLevel = getLevel();
-                mRssi = result.level;
-                if (getLevel() != oldLevel) {
-                    notifyChanged();
-                }
-            }
-            // This flag only comes from scans, is not easily saved in config
-            if (security == SECURITY_PSK) {
-                pskType = getPskType(result);
-            }
-            mScanResult = result;
-            refresh();
-            return true;
-        }
-        return false;
-    }
-
-    /** Return whether the given {@link WifiInfo} is for this access point. */
-    private boolean isInfoForThisAccessPoint(WifiInfo info) {
-        if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
-            return networkId == info.getNetworkId();
-        } else {
-            // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
-            // (Note that we only do this if the WifiConfiguration explicitly equals INVALID).
-            // TODO: Handle hex string SSIDs.
-            return ssid.equals(removeDoubleQuotes(info.getSSID()));
-        }
-    }
-
-    void update(WifiInfo info, NetworkInfo networkInfo) {
-        boolean reorder = false;
-        if (info != null && isInfoForThisAccessPoint(info)) {
-            reorder = (mInfo == null);
-            mRssi = info.getRssi();
-            mInfo = info;
-            mNetworkInfo = networkInfo;
-            refresh();
-        } else if (mInfo != null) {
-            reorder = true;
-            mInfo = null;
-            mNetworkInfo = null;
-            refresh();
-        }
-        if (reorder) {
-            notifyHierarchyChanged();
-        }
-    }
-
-    int getLevel() {
-        if (mRssi == Integer.MAX_VALUE) {
-            return -1;
-        }
-        return WifiManager.calculateSignalLevel(mRssi, 4);
-    }
-
-    WifiConfiguration getConfig() {
-        return mConfig;
-    }
-
-    WifiInfo getInfo() {
-        return mInfo;
-    }
-
-    NetworkInfo getNetworkInfo() {
-        return mNetworkInfo;
-    }
-
-    DetailedState getState() {
-        return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null;
-    }
-
-    static String removeDoubleQuotes(String string) {
-        int length = string.length();
-        if ((length > 1) && (string.charAt(0) == '"')
-                && (string.charAt(length - 1) == '"')) {
-            return string.substring(1, length - 1);
-        }
-        return string;
-    }
-
-    static String convertToQuotedString(String string) {
-        return "\"" + string + "\"";
-    }
-
-    /**
-     * Shows or Hides the Summary of an AccessPoint.
-     *
-     * @param showSummary true will show the summary, false will hide the summary
-     */
-    public void setShowSummary(boolean showSummary) {
-        this.showSummary = showSummary;
-        if (mSummaryView != null) {
-            mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE);
-        } // otherwise, will be handled in onBindView.
-    }
-
-    /**
-     * Returns the visibility status of the WifiConfiguration.
-     *
-     * @return autojoin debugging information
-     * TODO: use a string formatter
-     * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"]
-     * For instance [-40,5/-30,2]
-     */
-    private String getVisibilityStatus() {
-        StringBuilder visibility = new StringBuilder();
-        StringBuilder scans24GHz = null;
-        StringBuilder scans5GHz = null;
-        String bssid = null;
-
-        long now = System.currentTimeMillis();
-
-        if (mInfo != null) {
-            bssid = mInfo.getBSSID();
-            if (bssid != null) {
-                visibility.append(" ").append(bssid);
-            }
-            visibility.append(" rssi=").append(mInfo.getRssi());
-            visibility.append(" ");
-            visibility.append(" score=").append(mInfo.score);
-            visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate));
-            visibility.append(String.format("%.1f,", mInfo.txRetriesRate));
-            visibility.append(String.format("%.1f ", mInfo.txBadRate));
-            visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate));
-        }
-
-        if (mScanResultCache != null) {
-            int rssi5 = WifiConfiguration.INVALID_RSSI;
-            int rssi24 = WifiConfiguration.INVALID_RSSI;
-            int num5 = 0;
-            int num24 = 0;
-            int numBlackListed = 0;
-            int n24 = 0; // Number scan results we included in the string
-            int n5 = 0; // Number scan results we included in the string
-            Map<String, ScanResult> list = mScanResultCache.snapshot();
-            // TODO: sort list by RSSI or age
-            for (ScanResult result : list.values()) {
-                if (result.seen == 0)
-                    continue;
-
-                if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++;
-
-                if (result.frequency >= LOWER_FREQ_5GHZ
-                        && result.frequency <= HIGHER_FREQ_5GHZ) {
-                    // Strictly speaking: [4915, 5825]
-                    // number of known BSSID on 5GHz band
-                    num5 = num5 + 1;
-                } else if (result.frequency >= LOWER_FREQ_24GHZ
-                        && result.frequency <= HIGHER_FREQ_24GHZ) {
-                    // Strictly speaking: [2412, 2482]
-                    // number of known BSSID on 2.4Ghz band
-                    num24 = num24 + 1;
-                }
-
-                // Ignore results seen, older than 20 seconds
-                if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue;
-
-                if (result.frequency >= LOWER_FREQ_5GHZ
-                        && result.frequency <= HIGHER_FREQ_5GHZ) {
-                    if (result.level > rssi5) {
-                        rssi5 = result.level;
-                    }
-                    if (n5 < 4) {
-                        if (scans5GHz == null) scans5GHz = new StringBuilder();
-                        scans5GHz.append(" \n{").append(result.BSSID);
-                        if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*");
-                        scans5GHz.append("=").append(result.frequency);
-                        scans5GHz.append(",").append(result.level);
-                        if (result.autoJoinStatus != 0) {
-                            scans5GHz.append(",st=").append(result.autoJoinStatus);
-                        }
-                        if (result.numIpConfigFailures != 0) {
-                            scans5GHz.append(",ipf=").append(result.numIpConfigFailures);
-                        }
-                        scans5GHz.append("}");
-                        n5++;
-                    }
-                } else if (result.frequency >= LOWER_FREQ_24GHZ
-                        && result.frequency <= HIGHER_FREQ_24GHZ) {
-                    if (result.level > rssi24) {
-                        rssi24 = result.level;
-                    }
-                    if (n24 < 4) {
-                        if (scans24GHz == null) scans24GHz = new StringBuilder();
-                        scans24GHz.append(" \n{").append(result.BSSID);
-                        if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*");
-                        scans24GHz.append("=").append(result.frequency);
-                        scans24GHz.append(",").append(result.level);
-                        if (result.autoJoinStatus != 0) {
-                            scans24GHz.append(",st=").append(result.autoJoinStatus);
-                        }
-                        if (result.numIpConfigFailures != 0) {
-                            scans24GHz.append(",ipf=").append(result.numIpConfigFailures);
-                        }
-                        scans24GHz.append("}");
-                        n24++;
-                    }
-                }
-            }
-            visibility.append(" [");
-            if (num24 > 0) {
-                visibility.append("(").append(num24).append(")");
-                if (n24 <= 4) {
-                    if (scans24GHz != null) {
-                        visibility.append(scans24GHz.toString());
-                    }
-                } else {
-                    visibility.append("max=").append(rssi24);
-                    if (scans24GHz != null) {
-                        visibility.append(",").append(scans24GHz.toString());
-                    }
-                }
-            }
-            visibility.append(";");
-            if (num5 > 0) {
-                visibility.append("(").append(num5).append(")");
-                if (n5 <= 4) {
-                    if (scans5GHz != null) {
-                        visibility.append(scans5GHz.toString());
-                    }
-                } else {
-                    visibility.append("max=").append(rssi5);
-                    if (scans5GHz != null) {
-                        visibility.append(",").append(scans5GHz.toString());
-                    }
-                }
-            }
-            if (numBlackListed > 0)
-                visibility.append("!").append(numBlackListed);
-            visibility.append("]");
-        } else {
-            if (mRssi != Integer.MAX_VALUE) {
-                visibility.append(" rssi=");
-                visibility.append(mRssi);
-                if (mScanResult != null) {
-                    visibility.append(", f=");
-                    visibility.append(mScanResult.frequency);
-                }
-            }
-        }
-
-        return visibility.toString();
-    }
-
-    /**
-     * Return whether this is the active connection.
-     * For ephemeral connections (networkId is invalid), this returns false if the network is
-     * disconnected.
-     */
-    boolean isActive() {
-        return mNetworkInfo != null &&
-                (networkId != WifiConfiguration.INVALID_NETWORK_ID ||
-                 mNetworkInfo.getState() != State.DISCONNECTED);
-    }
-
-    /**
-     * Updates the title and summary; may indirectly call notifyChanged().
-     */
-    private void refresh() {
-        setTitle(ssid);
-
-        final Context context = getContext();
-        updateIcon(getLevel(), context);
-
-        // Force new summary
-        setSummary(null);
-
-        // Update to new summary
-        StringBuilder summary = new StringBuilder();
-
-        if (isActive()) { // This is the active connection
-            summary.append(Summary.get(context, getState(),
-                    networkId == WifiConfiguration.INVALID_NETWORK_ID));
-        } else if (mConfig != null
-                && mConfig.hasNoInternetAccess()) {
-            summary.append(context.getString(R.string.wifi_no_internet));
-        } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED &&
-                mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON)
-               || mConfig.autoJoinStatus
-                >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) {
-            if (mConfig.autoJoinStatus
-                    >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
-                if (mConfig.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE) {
-                    summary.append(context.getString(R.string.wifi_disabled_network_failure));
-                } else if (mConfig.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE) {
-                    summary.append(context.getString(R.string.wifi_disabled_password_failure));
-                } else {
-                    summary.append(context.getString(R.string.wifi_disabled_wifi_failure));
-                }
-            } else {
-                switch (mConfig.disableReason) {
-                    case WifiConfiguration.DISABLED_AUTH_FAILURE:
-                        summary.append(context.getString(R.string.wifi_disabled_password_failure));
-                        break;
-                    case WifiConfiguration.DISABLED_DHCP_FAILURE:
-                    case WifiConfiguration.DISABLED_DNS_FAILURE:
-                        summary.append(context.getString(R.string.wifi_disabled_network_failure));
-                        break;
-                    case WifiConfiguration.DISABLED_UNKNOWN_REASON:
-                    case WifiConfiguration.DISABLED_ASSOCIATION_REJECT:
-                        summary.append(context.getString(R.string.wifi_disabled_generic));
-                        break;
-                }
-            }
-        } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
-            summary.append(context.getString(R.string.wifi_not_in_range));
-        } else { // In range, not disabled.
-            if (mConfig != null) { // Is saved network
-                summary.append(context.getString(R.string.wifi_remembered));
-            }
-        }
-
-        if (WifiSettings.mVerboseLogging > 0) {
-            // Add RSSI/band information for this config, what was seen up to 6 seconds ago
-            // verbose WiFi Logging is only turned on thru developers settings
-            if (mInfo != null && mNetworkInfo != null) { // This is the active connection
-                summary.append(" f=" + Integer.toString(mInfo.getFrequency()));
-            }
-            summary.append(" " + getVisibilityStatus());
-            if (mConfig != null && mConfig.autoJoinStatus > 0) {
-                summary.append(" (" + mConfig.autoJoinStatus);
-                if (mConfig.blackListTimestamp > 0) {
-                    long now = System.currentTimeMillis();
-                    long diff = (now - mConfig.blackListTimestamp)/1000;
-                    long sec = diff%60; //seconds
-                    long min = (diff/60)%60; //minutes
-                    long hour = (min/60)%60; //hours
-                    summary.append(", ");
-                    if (hour > 0) summary.append(Long.toString(hour) + "h ");
-                    summary.append( Long.toString(min) + "m ");
-                    summary.append( Long.toString(sec) + "s ");
-                }
-                summary.append(")");
-            }
-            if (mConfig != null && mConfig.numIpConfigFailures > 0) {
-                summary.append(" ipf=").append(mConfig.numIpConfigFailures);
-            }
-            if (mConfig != null && mConfig.numConnectionFailures > 0) {
-                summary.append(" cf=").append(mConfig.numConnectionFailures);
-            }
-            if (mConfig != null && mConfig.numAuthFailures > 0) {
-                summary.append(" authf=").append(mConfig.numAuthFailures);
-            }
-            if (mConfig != null && mConfig.numNoInternetAccessReports > 0) {
-                summary.append(" noInt=").append(mConfig.numNoInternetAccessReports);
-            }
-        }
-
-        if (summary.length() > 0) {
-            setSummary(summary.toString());
-            setShowSummary(true);
-        } else {
-            setShowSummary(false);
-        }
-    }
-
-    /**
-     * Generate and save a default wifiConfiguration with common values.
-     * Can only be called for unsecured networks.
-     * @hide
-     */
-    protected void generateOpenNetworkConfig() {
-        if (security != SECURITY_NONE)
-            throw new IllegalStateException();
-        if (mConfig != null)
-            return;
-        mConfig = new WifiConfiguration();
-        mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
-        mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
-    }
-}
diff --git a/src/com/android/settings/wifi/AccessPointPreference.java b/src/com/android/settings/wifi/AccessPointPreference.java
new file mode 100644
index 0000000..3975434
--- /dev/null
+++ b/src/com/android/settings/wifi/AccessPointPreference.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 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 android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.net.wifi.WifiConfiguration;
+import android.preference.Preference;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
+
+public class AccessPointPreference extends Preference {
+
+    private static final int[] STATE_SECURED = {
+        R.attr.state_encrypted
+    };
+    private static final int[] STATE_NONE = {};
+
+    private static int[] wifi_signal_attributes = { R.attr.wifi_signal };
+
+    private TextView mSummaryView;
+    private boolean showSummary = true;
+    private AccessPoint mAccessPoint;
+
+    public AccessPointPreference(AccessPoint accessPoint, Context context) {
+        super(context);
+        mAccessPoint = accessPoint;
+        mAccessPoint.setTag(this);
+        refresh();
+    }
+
+    public AccessPoint getAccessPoint() {
+        return mAccessPoint;
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+        updateIcon(mAccessPoint.getLevel(), getContext());
+
+        mSummaryView = (TextView) view.findViewById(com.android.internal.R.id.summary);
+        mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE);
+
+        notifyChanged();
+    }
+
+    public void showAppIcon() {
+        PackageManager pm = getContext().getPackageManager();
+        String systemName = pm.getNameForUid(android.os.Process.SYSTEM_UID);
+        WifiConfiguration mConfig = mAccessPoint.getConfig();
+
+        Drawable drawable = pm.getDefaultActivityIcon();
+        if (mConfig == null) {
+            drawable.setAlpha(0);
+        } else if (mConfig.creatorName.equals(systemName)) {
+            drawable = getContext().getApplicationInfo().loadIcon(pm);
+        } else {
+            try {
+                drawable = pm.getApplicationIcon(mConfig.creatorName);
+            } catch (NameNotFoundException nnfe) {
+                // use default app icon
+            }
+        }
+
+        setIcon(drawable);
+    }
+
+    protected void updateIcon(int level, Context context) {
+        if (level == -1) {
+            setIcon(null);
+        } else {
+            Drawable drawable = getIcon();
+
+            if (drawable == null) {
+                // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
+                // set the icon (drawable) to that state's drawable.
+                StateListDrawable sld = (StateListDrawable) context.getTheme()
+                        .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
+                // If sld is null then we are indexing and therefore do not have access to
+                // (nor need to display) the drawable.
+                if (sld != null) {
+                    sld.setState((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
+                            ? STATE_SECURED
+                            : STATE_NONE);
+                    drawable = sld.getCurrent();
+                    setIcon(drawable);
+                }
+            }
+
+            if (drawable != null) {
+                drawable.setLevel(level);
+            }
+        }
+    }
+
+    /**
+     * Shows or Hides the Summary of an AccessPoint.
+     *
+     * @param showSummary true will show the summary, false will hide the summary
+     */
+    public void setShowSummary(boolean showSummary) {
+        this.showSummary = showSummary;
+        if (mSummaryView != null) {
+            mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE);
+        } // otherwise, will be handled in onBindView.
+    }
+
+    /**
+     * Updates the title and summary; may indirectly call notifyChanged().
+     */
+    public void refresh() {
+        setTitle(mAccessPoint.getSsid());
+
+        final Context context = getContext();
+        updateIcon(mAccessPoint.getLevel(), context);
+
+        // Force new summary
+        setSummary(null);
+
+        String summary = mAccessPoint.getSummary();
+        if (summary.length() > 0) {
+            setSummary(summary);
+            setShowSummary(true);
+        } else {
+            setShowSummary(false);
+        }
+    }
+
+    public void onLevelChanged() {
+        notifyChanged();
+    }
+
+}
diff --git a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
index bea720c..e92bda7 100644
--- a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
+++ b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
@@ -20,28 +20,22 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.Resources;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceScreen;
-
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.search.Indexable;
-import com.android.settings.search.SearchIndexableRaw;
-
 import android.util.Log;
-import android.view.View;
 
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
+import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.WifiTracker;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * UI to manage saved networks/access points.
@@ -88,14 +82,17 @@
         PreferenceScreen preferenceScreen = getPreferenceScreen();
         final Context context = getActivity();
 
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        final List<AccessPoint> accessPoints = constructSavedAccessPoints(context, mWifiManager);
+        final List<AccessPoint> accessPoints = WifiTracker.getCurrentAccessPoints(context, true,
+                false);
 
         preferenceScreen.removeAll();
 
         final int accessPointsSize = accessPoints.size();
         for (int i = 0; i < accessPointsSize; ++i){
-            preferenceScreen.addPreference(accessPoints.get(i));
+            AccessPointPreference preference = new AccessPointPreference(accessPoints.get(i),
+                    context);
+            preference.setShowSummary(false);
+            preferenceScreen.addPreference(preference);
         }
 
         if(getPreferenceScreen().getPreferenceCount() < 1) {
@@ -103,62 +100,14 @@
         }
     }
 
-    private static List<AccessPoint> constructSavedAccessPoints(Context context,
-            WifiManager wifiManager){
-        List<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
-        Map<String, List<ScanResult>> resultsMap = new HashMap<String, List<ScanResult>>();
-
-        final List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
-        final List<ScanResult> scanResults = wifiManager.getScanResults();
-
-        if (configs != null) {
-            //Construct a Map for quick searching of a wifi network via ssid.
-            final int scanResultsSize = scanResults.size();
-            for (int i = 0; i < scanResultsSize; ++i){
-                final ScanResult result = scanResults.get(i);
-                List<ScanResult> res = resultsMap.get(result.SSID);
-
-                if(res == null){
-                    res = new ArrayList<ScanResult>();
-                    resultsMap.put(result.SSID, res);
-                }
-
-                res.add(result);
-            }
-
-            final int configsSize = configs.size();
-            for (int i = 0; i < configsSize; ++i){
-                WifiConfiguration config = configs.get(i);
-                if (config.selfAdded && config.numAssociation == 0) {
-                    continue;
-                }
-                AccessPoint accessPoint = new AccessPoint(context, config);
-                final List<ScanResult> results = resultsMap.get(accessPoint.ssid);
-
-                accessPoint.setShowSummary(false);
-                if(results != null){
-                    final int resultsSize = results.size();
-                    for (int j = 0; j < resultsSize; ++j){
-                        accessPoint.update(results.get(j));
-                        accessPoint.setIcon(null);
-                    }
-                }
-
-                accessPoints.add(accessPoint);
-            }
-        }
-
-        return accessPoints;
-    }
-
-    private void showDialog(AccessPoint accessPoint, boolean edit) {
+    private void showDialog(AccessPointPreference accessPoint, boolean edit) {
         if (mDialog != null) {
             removeDialog(WifiSettings.WIFI_DIALOG_ID);
             mDialog = null;
         }
 
         // Save the access point and edit mode
-        mDlgAccessPoint = accessPoint;
+        mDlgAccessPoint = accessPoint.getAccessPoint();
 
         showDialog(WifiSettings.WIFI_DIALOG_ID);
     }
@@ -198,16 +147,16 @@
     @Override
     public void onClick(DialogInterface dialogInterface, int button) {
         if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
-            mWifiManager.forget(mSelectedAccessPoint.networkId, null);
-            getPreferenceScreen().removePreference(mSelectedAccessPoint);
+            mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, null);
+            getPreferenceScreen().removePreference((Preference) mSelectedAccessPoint.getTag());
             mSelectedAccessPoint = null;
         }
     }
 
     @Override
     public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
-        if (preference instanceof AccessPoint) {
-            showDialog((AccessPoint) preference, false);
+        if (preference instanceof AccessPointPreference) {
+            showDialog((AccessPointPreference) preference, false);
             return true;
         } else{
             return super.onPreferenceTreeClick(screen, preference);
@@ -233,15 +182,13 @@
                 result.add(data);
 
                 // Add available Wi-Fi access points
-                WifiManager wifiManager =
-                        (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-                final List<AccessPoint> accessPoints =
-                        constructSavedAccessPoints(context, wifiManager);
+                final List<AccessPoint> accessPoints = WifiTracker.getCurrentAccessPoints(context,
+                        true, false);
 
                 final int accessPointsSize = accessPoints.size();
                 for (int i = 0; i < accessPointsSize; ++i){
                     data = new SearchIndexableRaw(context);
-                    data.title = accessPoints.get(i).getTitle().toString();
+                    data.title = accessPoints.get(i).getSsid();
                     data.screenTitle = title;
                     data.enabled = enabled;
                     result.add(data);
diff --git a/src/com/android/settings/wifi/Summary.java b/src/com/android/settings/wifi/Summary.java
deleted file mode 100644
index 123f64a..0000000
--- a/src/com/android/settings/wifi/Summary.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 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.DetailedState;
-
-class Summary {
-    static String get(Context context, String ssid, DetailedState state, boolean isEphemeral) {
-        if (state == DetailedState.CONNECTED && isEphemeral && ssid == null) {
-            // Special case for connected + ephemeral networks.
-            return context.getString(R.string.connected_via_wfa);
-        }
-
-        String[] formats = context.getResources().getStringArray((ssid == null)
-                ? R.array.wifi_status : R.array.wifi_status_with_ssid);
-        int index = state.ordinal();
-
-        if (index >= formats.length || formats[index].length() == 0) {
-            return null;
-        }
-        return String.format(formats[index], ssid);
-    }
-
-    static String get(Context context, DetailedState state, boolean isEphemeral) {
-        return get(context, null, state, isEphemeral);
-    }
-}
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 643ccb8..a5d0765 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -16,8 +16,6 @@
 
 package com.android.settings.wifi;
 
-import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
-
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.IpConfiguration;
@@ -27,7 +25,6 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
 import android.net.ProxyInfo;
-import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
 import android.net.wifi.WifiConfiguration;
@@ -38,7 +35,6 @@
 import android.net.wifi.WifiEnterpriseConfig.Phase2;
 import android.net.wifi.WifiInfo;
 import android.os.Handler;
-import android.os.UserHandle;
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.Editable;
@@ -60,6 +56,7 @@
 
 import com.android.settings.ProxySelector;
 import com.android.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
 
 import java.net.InetAddress;
 import java.net.Inet4Address;
@@ -156,7 +153,7 @@
         mView = view;
         mAccessPoint = accessPoint;
         mAccessPointSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE :
-                accessPoint.security;
+                accessPoint.getSecurity();
         mEdit = edit;
 
         mTextViewChangedHandler = new Handler();
@@ -209,12 +206,12 @@
 
             mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
         } else {
-            mConfigUi.setTitle(mAccessPoint.ssid);
+            mConfigUi.setTitle(mAccessPoint.getSsid());
 
             ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
 
             boolean showAdvancedFields = false;
-            if (mAccessPoint.networkId != INVALID_NETWORK_ID) {
+            if (mAccessPoint.isSaved()) {
                 WifiConfiguration config = mAccessPoint.getConfig();
                 if (config.getIpAssignment() == IpAssignment.STATIC) {
                     mIpSettingsSpinner.setSelection(STATIC_IP);
@@ -241,7 +238,7 @@
                 }
             }
 
-            if ((mAccessPoint.networkId == INVALID_NETWORK_ID && !mAccessPoint.isActive())
+            if ((!mAccessPoint.isSaved() && !mAccessPoint.isActive())
                     || mEdit) {
                 showSecurityFields();
                 showIpConfigFields();
@@ -258,16 +255,15 @@
             if (mEdit) {
                 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
             } else {
-                final DetailedState state = mAccessPoint.getState();
+                final DetailedState state = mAccessPoint.getDetailedState();
                 final String signalLevel = getSignalString();
 
                 if (state == null && signalLevel != null) {
                     mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect));
                 } else {
                     if (state != null) {
-                        addRow(group, R.string.wifi_status, Summary.get(mConfigUi.getContext(),
-                                state, mAccessPoint.networkId ==
-                                WifiConfiguration.INVALID_NETWORK_ID));
+                        addRow(group, R.string.wifi_status, AccessPoint.getSummary(
+                                mConfigUi.getContext(), state, !mAccessPoint.isSaved()));
                     }
 
                     if (signalLevel != null) {
@@ -301,14 +297,14 @@
                     addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
                     mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
                 }
-                if (mAccessPoint.networkId != INVALID_NETWORK_ID || mAccessPoint.isActive()) {
+                if (mAccessPoint.isSaved() || mAccessPoint.isActive()) {
                     mConfigUi.setForgetButton(res.getString(R.string.wifi_forget));
                 }
             }
         }
 
         if ((mEdit) || (mAccessPoint != null
-                && mAccessPoint.getState() == null && mAccessPoint.getLevel() != -1)){
+                && mAccessPoint.getDetailedState() == null && mAccessPoint.getLevel() != -1)){
             mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel));
         }else{
             mConfigUi.setCancelButton(res.getString(R.string.wifi_display_options_done));
@@ -353,7 +349,7 @@
         }
 
         if ((mSsidView != null && mSsidView.length() == 0) ||
-            ((mAccessPoint == null || mAccessPoint.networkId == INVALID_NETWORK_ID) &&
+            ((mAccessPoint == null || !mAccessPoint.isSaved()) &&
             passwordInvalid)) {
             enabled = false;
         } else {
@@ -367,7 +363,7 @@
     }
 
     /* package */ WifiConfiguration getConfig() {
-        if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID && !mEdit) {
+        if (mAccessPoint != null && mAccessPoint.isSaved() && !mEdit) {
             return null;
         }
 
@@ -378,11 +374,11 @@
                     mSsidView.getText().toString());
             // If the user adds a network manually, assume that it is hidden.
             config.hiddenSSID = true;
-        } else if (mAccessPoint.networkId == INVALID_NETWORK_ID) {
+        } else if (!mAccessPoint.isSaved()) {
             config.SSID = AccessPoint.convertToQuotedString(
-                    mAccessPoint.ssid);
+                    mAccessPoint.getSsid());
         } else {
-            config.networkId = mAccessPoint.networkId;
+            config.networkId = mAccessPoint.getConfig().networkId;
         }
 
         switch (mAccessPointSecurity) {
@@ -628,7 +624,7 @@
             ((CheckBox) mView.findViewById(R.id.show_password))
                 .setOnCheckedChangeListener(this);
 
-            if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
+            if (mAccessPoint != null && mAccessPoint.isSaved()) {
                 mPasswordView.setHint(R.string.wifi_unchanged);
             }
         }
@@ -652,7 +648,7 @@
             loadCertificates(mEapUserCertSpinner, Credentials.USER_PRIVATE_KEY);
 
             // Modifying an existing network
-            if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
+            if (mAccessPoint != null && mAccessPoint.isSaved()) {
                 WifiEnterpriseConfig enterpriseConfig = mAccessPoint.getConfig().enterpriseConfig;
                 int eapMethod = enterpriseConfig.getEapMethod();
                 int phase2Method = enterpriseConfig.getPhase2Method();
@@ -794,7 +790,7 @@
 
         mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE);
 
-        if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
+        if (mAccessPoint != null && mAccessPoint.isSaved()) {
             config = mAccessPoint.getConfig();
         }
 
@@ -846,7 +842,7 @@
 
         mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE);
 
-        if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
+        if (mAccessPoint != null && mAccessPoint.isSaved()) {
             config = mAccessPoint.getConfig();
         }
 
diff --git a/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java b/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java
index 440e694..62bb5e1 100644
--- a/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java
+++ b/src/com/android/settings/wifi/WifiConfigUiForSetupWizardXL.java
@@ -17,6 +17,7 @@
 package com.android.settings.wifi;
 
 import com.android.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
 
 import android.content.Context;
 import android.os.Handler;
diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java
index 942c5dd..1f03fe3 100644
--- a/src/com/android/settings/wifi/WifiDialog.java
+++ b/src/com/android/settings/wifi/WifiDialog.java
@@ -17,6 +17,7 @@
 package com.android.settings.wifi;
 
 import com.android.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
 
 import android.app.AlertDialog;
 import android.content.Context;
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index 0952941..754dbaa 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -31,9 +31,9 @@
 import android.widget.Toast;
 
 import com.android.settings.R;
-import com.android.settings.WirelessSettings;
 import com.android.settings.search.Index;
 import com.android.settings.widget.SwitchBar;
+import com.android.settingslib.WirelessUtils;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -196,7 +196,7 @@
             return;
         }
         // Show toast message if Wi-Fi is not allowed in airplane mode
-        if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
+        if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
             Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
             // Reset switch to off. No infinite check/listenenr loop.
             mSwitchBar.setChecked(false);
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 7b6d076..a4ecf0e 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -18,31 +18,22 @@
 
 import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
 import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
-
 import android.app.Activity;
 import android.app.Dialog;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
-import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WpsInfo;
 import android.nfc.NfcAdapter;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.UserHandle;
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
 import android.util.Log;
@@ -62,13 +53,13 @@
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
 import com.android.settings.search.SearchIndexableRaw;
+import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
+import com.android.settingslib.wifi.WifiTracker;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Two types of UI are provided here.
@@ -79,7 +70,8 @@
  * and menus.
  */
 public class WifiSettings extends RestrictedSettingsFragment
-        implements DialogInterface.OnClickListener, Indexable  {
+        implements DialogInterface.OnClickListener, Indexable, WifiTracker.WifiListener,
+        AccessPointListener {
 
     private static final String TAG = "WifiSettings";
 
@@ -100,20 +92,13 @@
     private static final int WPS_PIN_DIALOG_ID = 3;
     private static final int WRITE_NFC_DIALOG_ID = 6;
 
-    // Combo scans can take 5-6s to complete - set to 10s.
-    private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
-
     // Instance state keys
     private static final String SAVE_DIALOG_EDIT_MODE = "edit_mode";
     private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state";
 
     private static boolean savedNetworksExist;
 
-    private final IntentFilter mFilter;
-    private final BroadcastReceiver mReceiver;
-    private final Scanner mScanner;
-
-    /* package */ WifiManager mWifiManager;
+    protected WifiManager mWifiManager;
     private WifiManager.ActionListener mConnectListener;
     private WifiManager.ActionListener mSaveListener;
     private WifiManager.ActionListener mForgetListener;
@@ -122,11 +107,6 @@
     // An access point being editted is stored here.
     private AccessPoint mSelectedAccessPoint;
 
-    private NetworkInfo mLastNetworkInfo;
-    private WifiInfo mLastInfo;
-
-    private final AtomicBoolean mConnected = new AtomicBoolean(false);
-
     private WifiDialog mDialog;
     private WriteWifiConfigToNfcDialog mWifiToNfcDialog;
 
@@ -150,98 +130,20 @@
     private AccessPoint mDlgAccessPoint;
     private Bundle mAccessPointSavedState;
 
-    /** verbose logging flag. this flag is set thru developer debugging options
-     * and used so as to assist with in-the-field WiFi connectivity debugging  */
-    public static int mVerboseLogging = 0;
+    private WifiTracker mWifiTracker;
 
     /* End of "used in Wifi Setup context" */
 
-    /** A restricted multimap for use in constructAccessPoints */
-    private static class Multimap<K,V> {
-        private final HashMap<K,List<V>> store = new HashMap<K,List<V>>();
-        /** retrieve a non-null list of values with key K */
-        List<V> getAll(K key) {
-            List<V> values = store.get(key);
-            return values != null ? values : Collections.<V>emptyList();
-        }
-
-        void put(K key, V val) {
-            List<V> curVals = store.get(key);
-            if (curVals == null) {
-                curVals = new ArrayList<V>(3);
-                store.put(key, curVals);
-            }
-            curVals.add(val);
-        }
-    }
-
-    private static class Scanner extends Handler {
-        private int mRetry = 0;
-        private WifiSettings mWifiSettings = null;
-
-        Scanner(WifiSettings wifiSettings) {
-            mWifiSettings = wifiSettings;
-        }
-
-        void resume() {
-            if (!hasMessages(0)) {
-                sendEmptyMessage(0);
-            }
-        }
-
-        void forceScan() {
-            removeMessages(0);
-            sendEmptyMessage(0);
-        }
-
-        void pause() {
-            mRetry = 0;
-            removeMessages(0);
-        }
-
-        @Override
-        public void handleMessage(Message message) {
-            if (mWifiSettings.mWifiManager.startScan()) {
-                mRetry = 0;
-            } else if (++mRetry >= 3) {
-                mRetry = 0;
-                Activity activity = mWifiSettings.getActivity();
-                if (activity != null) {
-                    Toast.makeText(activity, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
-                }
-                return;
-            }
-            sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
-        }
-    }
-
     public WifiSettings() {
         super(DISALLOW_CONFIG_WIFI);
-        mFilter = new IntentFilter();
-        mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-        mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
-        mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
-        mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
-        mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
-        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-
-        mReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                handleEvent(intent);
-            }
-        };
-
-        mScanner = new Scanner(this);
     }
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
-        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+        mWifiTracker = new WifiTracker(getActivity(), this, true, true);
+        mWifiManager = mWifiTracker.getManager();
 
         mConnectListener = new WifiManager.ActionListener() {
                                    @Override
@@ -321,14 +223,14 @@
 
         if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) {
             String ssid = intent.getStringExtra(EXTRA_START_CONNECT_SSID);
-            updateAccessPoints();
+            onAccessPointsChanged();
             PreferenceScreen preferenceScreen = getPreferenceScreen();
             for (int i = 0; i < preferenceScreen.getPreferenceCount(); i++) {
                 Preference preference = preferenceScreen.getPreference(i);
-                if (preference instanceof AccessPoint) {
-                    AccessPoint accessPoint = (AccessPoint) preference;
-                    if (ssid.equals(accessPoint.ssid) && accessPoint.networkId == -1
-                            && accessPoint.security != AccessPoint.SECURITY_NONE) {
+                if (preference instanceof AccessPointPreference) {
+                    AccessPoint accessPoint = ((AccessPointPreference) preference).getAccessPoint();
+                    if (ssid.equals(accessPoint.getSsid()) && !accessPoint.isSaved()
+                            && accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
                         onPreferenceTreeClick(preferenceScreen, preference);
                         break;
                     }
@@ -370,8 +272,7 @@
             mWifiEnabler.resume(activity);
         }
 
-        activity.registerReceiver(mReceiver, mFilter);
-        updateAccessPoints();
+        mWifiTracker.startTracking();
     }
 
     @Override
@@ -381,8 +282,7 @@
             mWifiEnabler.pause();
         }
 
-        getActivity().unregisterReceiver(mReceiver);
-        mScanner.pause();
+        mWifiTracker.stopTracking();
     }
 
     @Override
@@ -398,7 +298,7 @@
      * @param menu
      */
     void addOptionsMenuItems(Menu menu) {
-        final boolean wifiIsEnabled = mWifiManager.isWifiEnabled();
+        final boolean wifiIsEnabled = mWifiTracker.isWifiEnabled();
         TypedArray ta = getActivity().getTheme().obtainStyledAttributes(
                 new int[] {R.attr.ic_menu_add, R.attr.ic_wps});
         menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network)
@@ -463,12 +363,10 @@
                 showDialog(WPS_PIN_DIALOG_ID);
                 return true;
             case MENU_ID_SCAN:
-                if (mWifiManager.isWifiEnabled()) {
-                    mScanner.forceScan();
-                }
+                mWifiTracker.forceScan();
                 return true;
             case MENU_ID_ADD_NETWORK:
-                if (mWifiManager.isWifiEnabled()) {
+                if (mWifiTracker.isWifiEnabled()) {
                     onAddNetworkPressed();
                 }
                 return true;
@@ -502,7 +400,7 @@
                 } else {
                     showAppMenuItem.setTitle(R.string.wifi_menu_apps);
                 }
-                updateAccessPoints();
+                onAccessPointsChanged();
                 return true;
         }
         return super.onOptionsItemSelected(item);
@@ -514,28 +412,24 @@
             Preference preference = (Preference) getListView().getItemAtPosition(
                     ((AdapterContextMenuInfo) info).position);
 
-            if (preference instanceof AccessPoint) {
-                mSelectedAccessPoint = (AccessPoint) preference;
-                menu.setHeaderTitle(mSelectedAccessPoint.ssid);
-                if (mSelectedAccessPoint.getLevel() != -1) {
-                    if (mSelectedAccessPoint.getState() == null) {
-                        menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
-                    }
+            if (preference instanceof AccessPointPreference) {
+                mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint();
+                menu.setHeaderTitle(mSelectedAccessPoint.getSsid());
+                if (mSelectedAccessPoint.isConnectable()) {
+                    menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
                 }
 
-                if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID ||
-                        (mSelectedAccessPoint.getNetworkInfo() != null &&
-                        mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED)) {
+                if (mSelectedAccessPoint.isSaved() || mSelectedAccessPoint.isEphemeral()) {
                     // Allow forgetting a network if either the network is saved or ephemerally
                     // connected. (In the latter case, "forget" blacklists the network so it won't
                     // be used again, ephemerally).
                     menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
                 }
-                if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
+                if (mSelectedAccessPoint.isSaved()) {
                     menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
                     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
                     if (nfcAdapter != null && nfcAdapter.isEnabled() &&
-                            mSelectedAccessPoint.security != AccessPoint.SECURITY_NONE) {
+                            mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
                         // Only allow writing of NFC tags for password-protected networks.
                         menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc);
                     }
@@ -551,9 +445,9 @@
         }
         switch (item.getItemId()) {
             case MENU_ID_CONNECT: {
-                if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
-                    connect(mSelectedAccessPoint.networkId);
-                } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
+                if (mSelectedAccessPoint.isSaved()) {
+                    connect(mSelectedAccessPoint.getConfig());
+                } else if (mSelectedAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
                     /** Bypass dialog for unsecured networks */
                     mSelectedAccessPoint.generateOpenNetworkConfig();
                     connect(mSelectedAccessPoint.getConfig());
@@ -580,12 +474,11 @@
 
     @Override
     public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
-        if (preference instanceof AccessPoint) {
-            mSelectedAccessPoint = (AccessPoint) preference;
+        if (preference instanceof AccessPointPreference) {
+            mSelectedAccessPoint = ((AccessPointPreference) preference).getAccessPoint();
             /** Bypass dialog for unsecured, unsaved, and inactive networks */
-            if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
-                    mSelectedAccessPoint.networkId == INVALID_NETWORK_ID &&
-                    !mSelectedAccessPoint.isActive()) {
+            if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE &&
+                    !mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) {
                 mSelectedAccessPoint.generateOpenNetworkConfig();
                 if (!savedNetworksExist) {
                     savedNetworksExist = true;
@@ -651,7 +544,8 @@
      * Shows the latest access points available with supplemental information like
      * the strength of network and the security for it.
      */
-    protected void updateAccessPoints() {
+    @Override
+    public void onAccessPointsChanged() {
         // Safeguard from some delayed event handling
         if (getActivity() == null) return;
 
@@ -661,28 +555,27 @@
         }
         final int wifiState = mWifiManager.getWifiState();
 
-        //when we update the screen, check if verbose logging has been turned on or off
-        mVerboseLogging = mWifiManager.getVerboseLoggingLevel();
-
         switch (wifiState) {
             case WifiManager.WIFI_STATE_ENABLED:
                 // AccessPoints are automatically sorted with TreeSet.
                 final Collection<AccessPoint> accessPoints =
-                        constructAccessPoints(getActivity(), mWifiManager, mLastInfo,
-                                mLastNetworkInfo);
+                        mWifiTracker.getAccessPoints();
                 getPreferenceScreen().removeAll();
                 if (accessPoints.size() == 0) {
                     addMessagePreference(R.string.wifi_empty_list_wifi_on);
                 }
 
                 for (AccessPoint accessPoint : accessPoints) {
-                    if (showAppIcons) {
-                        accessPoint.showAppIcon();
-                    }
-
                     // Ignore access points that are out of range.
                     if (accessPoint.getLevel() != -1) {
-                        getPreferenceScreen().addPreference(accessPoint);
+                        AccessPointPreference preference = new AccessPointPreference(accessPoint,
+                                getActivity());
+                        if (showAppIcons) {
+                            preference.showAppIcon();
+                        }
+
+                        getPreferenceScreen().addPreference(preference);
+                        accessPoint.setListener(this);
                     }
                 }
                 break;
@@ -699,6 +592,11 @@
                 setOffMessage();
                 break;
         }
+        // Update "Saved Networks" menu option.
+        if (savedNetworksExist != mWifiTracker.doSavedNetworksExist()) {
+            savedNetworksExist = !savedNetworksExist;
+            getActivity().invalidateOptionsMenu();
+        }
     }
 
     protected TextView initEmptyView() {
@@ -732,127 +630,14 @@
         getPreferenceScreen().removeAll();
     }
 
-    /** Returns sorted list of access points */
-    private static List<AccessPoint> constructAccessPoints(Context context,
-            WifiManager wifiManager, WifiInfo lastInfo, NetworkInfo lastNetworkInfo) {
-        ArrayList<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
-        /** Lookup table to more quickly update AccessPoints by only considering objects with the
-         * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
-        Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
-
-        final List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
-        if (configs != null) {
-            // Update "Saved Networks" menu option.
-            if (savedNetworksExist != (configs.size() > 0)) {
-                savedNetworksExist = !savedNetworksExist;
-                if (context instanceof Activity) {
-                    ((Activity) context).invalidateOptionsMenu();
-                }
-            }
-            for (WifiConfiguration config : configs) {
-                if (config.selfAdded && config.numAssociation == 0) {
-                    continue;
-                }
-                AccessPoint accessPoint = new AccessPoint(context, config);
-                if (lastInfo != null && lastNetworkInfo != null) {
-                    accessPoint.update(lastInfo, lastNetworkInfo);
-                }
-                accessPoints.add(accessPoint);
-                apMap.put(accessPoint.ssid, accessPoint);
-            }
-        }
-
-        final List<ScanResult> results = wifiManager.getScanResults();
-        if (results != null) {
-            for (ScanResult result : results) {
-                // Ignore hidden and ad-hoc networks.
-                if (result.SSID == null || result.SSID.length() == 0 ||
-                        result.capabilities.contains("[IBSS]")) {
-                    continue;
-                }
-
-                boolean found = false;
-                for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
-                    if (accessPoint.update(result))
-                        found = true;
-                }
-                if (!found) {
-                    AccessPoint accessPoint = new AccessPoint(context, result);
-                    if (lastInfo != null && lastNetworkInfo != null) {
-                        accessPoint.update(lastInfo, lastNetworkInfo);
-                    }
-                    accessPoints.add(accessPoint);
-                    apMap.put(accessPoint.ssid, accessPoint);
-                }
-            }
-        }
-
-        // Pre-sort accessPoints to speed preference insertion
-        Collections.sort(accessPoints);
-        return accessPoints;
-    }
-
-    private void handleEvent(Intent intent) {
-        String action = intent.getAction();
-        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
-            updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                    WifiManager.WIFI_STATE_UNKNOWN));
-        } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
-                WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
-                WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
-                updateAccessPoints();
-        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
-            NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
-                    WifiManager.EXTRA_NETWORK_INFO);
-            mConnected.set(info.isConnected());
-            changeNextButtonState(info.isConnected());
-            updateAccessPoints();
-            updateNetworkInfo(info);
-        } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
-            updateNetworkInfo(null);
-        }
-    }
-
-    private void updateNetworkInfo(NetworkInfo networkInfo) {
-        /* sticky broadcasts can call this when wifi is disabled */
-        if (!mWifiManager.isWifiEnabled()) {
-            mScanner.pause();
-            return;
-        }
-
-        if (networkInfo != null &&
-                networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) {
-            mScanner.pause();
-        } else {
-            mScanner.resume();
-        }
-
-        mLastInfo = mWifiManager.getConnectionInfo();
-        if (networkInfo != null) {
-            mLastNetworkInfo = networkInfo;
-        }
-
-        for (int i = getPreferenceScreen().getPreferenceCount() - 1; i >= 0; --i) {
-            // Maybe there's a WifiConfigPreference
-            Preference preference = getPreferenceScreen().getPreference(i);
-            if (preference instanceof AccessPoint) {
-                final AccessPoint accessPoint = (AccessPoint) preference;
-                accessPoint.update(mLastInfo, mLastNetworkInfo);
-            }
-        }
-    }
-
-    private void updateWifiState(int state) {
+    @Override
+    public void onWifiStateChanged(int state) {
         Activity activity = getActivity();
         if (activity != null) {
             activity.invalidateOptionsMenu();
         }
 
         switch (state) {
-            case WifiManager.WIFI_STATE_ENABLED:
-                mScanner.resume();
-                return; // not break, to avoid the call to pause() below
-
             case WifiManager.WIFI_STATE_ENABLING:
                 addMessagePreference(R.string.wifi_starting);
                 break;
@@ -861,10 +646,11 @@
                 setOffMessage();
                 break;
         }
+    }
 
-        mLastInfo = null;
-        mLastNetworkInfo = null;
-        mScanner.pause();
+    @Override
+    public void onConnectedChanged() {
+        changeNextButtonState(mWifiTracker.isConnected());
     }
 
     /**
@@ -896,8 +682,8 @@
 
         if (config == null) {
             if (mSelectedAccessPoint != null
-                    && mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
-                connect(mSelectedAccessPoint.networkId);
+                    && mSelectedAccessPoint.isSaved()) {
+                connect(mSelectedAccessPoint.getConfig());
             }
         } else if (config.networkId != INVALID_NETWORK_ID) {
             if (mSelectedAccessPoint != null) {
@@ -911,32 +697,25 @@
             }
         }
 
-        if (mWifiManager.isWifiEnabled()) {
-            mScanner.resume();
-        }
-        updateAccessPoints();
+        mWifiTracker.resumeScanning();
     }
 
     /* package */ void forget() {
-        if (mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
+        if (!mSelectedAccessPoint.isSaved()) {
             if (mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) {
                 // Network is active but has no network ID - must be ephemeral.
                 mWifiManager.disableEphemeralNetwork(
-                        AccessPoint.convertToQuotedString(mSelectedAccessPoint.ssid));
+                        AccessPoint.convertToQuotedString(mSelectedAccessPoint.getSsid()));
             } else {
                 // Should not happen, but a monkey seems to trigger it
                 Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig());
                 return;
             }
         } else {
-            mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);
+            mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener);
         }
 
-
-        if (mWifiManager.isWifiEnabled()) {
-            mScanner.resume();
-        }
-        updateAccessPoints();
+        mWifiTracker.resumeScanning();
 
         // We need to rename/replace "Next" button in wifi setup context.
         changeNextButtonState(false);
@@ -954,9 +733,7 @@
      * Refreshes acccess points and ask Wifi module to scan networks again.
      */
     /* package */ void refreshAccessPoints() {
-        if (mWifiManager.isWifiEnabled()) {
-            mScanner.resume();
-        }
+        mWifiTracker.resumeScanning();
 
         getPreferenceScreen().removeAll();
     }
@@ -971,7 +748,7 @@
     }
 
     /* package */ int getAccessPointsCount() {
-        final boolean wifiIsEnabled = mWifiManager.isWifiEnabled();
+        final boolean wifiIsEnabled = mWifiTracker.isWifiEnabled();
         if (wifiIsEnabled) {
             return getPreferenceScreen().getPreferenceCount();
         } else {
@@ -983,18 +760,14 @@
      * Requests wifi module to pause wifi scan. May be ignored when the module is disabled.
      */
     /* package */ void pauseWifiScan() {
-        if (mWifiManager.isWifiEnabled()) {
-            mScanner.pause();
-        }
+        mWifiTracker.pauseScanning();
     }
 
     /**
      * Requests wifi module to resume wifi scan. May be ignored when the module is disabled.
      */
     /* package */ void resumeWifiScan() {
-        if (mWifiManager.isWifiEnabled()) {
-            mScanner.resume();
-        }
+        mWifiTracker.resumeScanning();
     }
 
     @Override
@@ -1002,6 +775,16 @@
         return R.string.help_url_wifi;
     }
 
+    @Override
+    public void onAccessPointChanged(AccessPoint accessPoint) {
+        ((AccessPointPreference) accessPoint.getTag()).refresh();
+    }
+
+    @Override
+    public void onLevelChanged(AccessPoint accessPoint) {
+        ((AccessPointPreference) accessPoint.getTag()).onLevelChanged();
+    }
+
     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
         new BaseSearchIndexProvider() {
             @Override
@@ -1016,16 +799,12 @@
                 data.keywords = res.getString(R.string.keywords_wifi);
                 result.add(data);
 
-                // Add available Wi-Fi access points
-                WifiManager wifiManager =
-                        (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+                // Add saved Wi-Fi access points
                 final Collection<AccessPoint> accessPoints =
-                        constructAccessPoints(context, wifiManager, null, null);
+                        WifiTracker.getCurrentAccessPoints(context, true, false);
                 for (AccessPoint accessPoint : accessPoints) {
-                    // We are indexing only the saved Wi-Fi networks.
-                    if (accessPoint.getConfig() == null) continue;
                     data = new SearchIndexableRaw(context);
-                    data.title = accessPoint.getTitle().toString();
+                    data.title = accessPoint.getSsid();
                     data.screenTitle = res.getString(R.string.wifi_settings);
                     data.enabled = enabled;
                     result.add(data);
diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
index d321945..efa56d7 100644
--- a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
+++ b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
@@ -95,8 +95,8 @@
     }
 
     @Override
-    protected void updateAccessPoints() {
-        super.updateAccessPoints();
+    public void onAccessPointsChanged() {
+        super.onAccessPointsChanged();
         updateFooter(getPreferenceScreen().getPreferenceCount() == 0);
     }
 
diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java
index 2588309..a3018a3 100644
--- a/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java
+++ b/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java
@@ -24,8 +24,6 @@
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
 import android.preference.PreferenceScreen;
 import android.text.TextUtils;
 import android.util.Log;
@@ -39,6 +37,7 @@
 import android.widget.TextView;
 
 import com.android.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
 
 import java.util.Collection;
 import java.util.EnumMap;
@@ -285,7 +284,7 @@
         default:  // DISCONNECTED, FAILED
             if (mScreenState != SCREEN_STATE_CONNECTED &&
                     mWifiSettings.getAccessPointsCount() > 0) {
-                showDisconnectedState(Summary.get(this, state, false /* isEphemeral */));
+                showDisconnectedState(AccessPoint.getSummary(this, state, false /* isEphemeral */));
             }
             break;
         }
@@ -422,8 +421,8 @@
         mScreenState = SCREEN_STATE_EDITING;
 
         if (selectedAccessPoint != null &&
-                (selectedAccessPoint.security == AccessPoint.SECURITY_WEP ||
-                        selectedAccessPoint.security == AccessPoint.SECURITY_PSK)) {
+                (selectedAccessPoint.getSecurity() == AccessPoint.SECURITY_WEP ||
+                        selectedAccessPoint.getSecurity() == AccessPoint.SECURITY_PSK)) {
             // We forcibly set edit as true so that users can modify every field if they want,
             // while config UI doesn't allow them to edit some of them when edit is false
             // (e.g. password field is hiden when edit==false).
@@ -446,17 +445,17 @@
 
             showDisconnectedProgressBar();
             showEditingButtonState();
-        } else if (selectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
-            mNetworkName = selectedAccessPoint.getTitle().toString();
+        } else if (selectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
+            mNetworkName = selectedAccessPoint.getSsid().toString();
 
             // onConnectButtonPressed() will change visibility status.
             mConnectButton.performClick();
         } else {
-            mNetworkName = selectedAccessPoint.getTitle().toString();
+            mNetworkName = selectedAccessPoint.getSsid().toString();
             showEditingTitle();
             showDisconnectedProgressBar();
             showEditingButtonState();
-            if (selectedAccessPoint.security == AccessPoint.SECURITY_EAP) {
+            if (selectedAccessPoint.getSecurity() == AccessPoint.SECURITY_EAP) {
                 onEapNetworkSelected();
             } else {
                 mConnectButton.setVisibility(View.VISIBLE);
@@ -657,8 +656,10 @@
         }
 
         for (AccessPoint accessPoint : accessPoints) {
-            accessPoint.setLayoutResource(R.layout.custom_preference);
-            preferenceScreen.addPreference(accessPoint);
+            AccessPointPreference preference = (AccessPointPreference) accessPoint.getTag();
+            if (preference == null) continue;
+            preference.setLayoutResource(R.layout.custom_preference);
+            preferenceScreen.addPreference(preference);
         }
     }
 
diff --git a/src/com/android/settings/wifi/WifiStatusTest.java b/src/com/android/settings/wifi/WifiStatusTest.java
index 48921d7..85afb7c 100644
--- a/src/com/android/settings/wifi/WifiStatusTest.java
+++ b/src/com/android/settings/wifi/WifiStatusTest.java
@@ -17,6 +17,7 @@
 package com.android.settings.wifi;
 
 import com.android.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
 
 import android.net.wifi.ScanResult;
 import java.net.HttpURLConnection;
@@ -297,7 +298,8 @@
     private void handleNetworkStateChanged(NetworkInfo networkInfo) {
         if (mWifiManager.isWifiEnabled()) {
             WifiInfo info = mWifiManager.getConnectionInfo();
-            String summary = Summary.get(this, info.getSSID(), networkInfo.getDetailedState(),
+            String summary = AccessPoint.getSummary(this, info.getSSID(),
+                    networkInfo.getDetailedState(),
                     info.getNetworkId() == WifiConfiguration.INVALID_NETWORK_ID);
             mNetworkState.setText(summary);
         }
diff --git a/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java b/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java
index 2667e0b..87850e5 100644
--- a/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java
+++ b/src/com/android/settings/wifi/WriteWifiConfigToNfcDialog.java
@@ -45,6 +45,7 @@
 import android.widget.TextView;
 
 import com.android.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
 
 import java.io.IOException;
 
@@ -121,7 +122,7 @@
 
         String password = mPasswordView.getText().toString();
         String wpsNfcConfigurationToken
-                = mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.networkId);
+                = mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.getConfig().networkId);
         String passwordHex = byteArrayToHexString(password.getBytes());
 
         String passwordLength = password.length() >= HEX_RADIX
@@ -224,9 +225,9 @@
     private void enableSubmitIfAppropriate() {
 
         if (mPasswordView != null) {
-            if (mAccessPoint.security == AccessPoint.SECURITY_WEP) {
+            if (mAccessPoint.getSecurity() == AccessPoint.SECURITY_WEP) {
                 mSubmitButton.setEnabled(mPasswordView.length() > 0);
-            } else if (mAccessPoint.security == AccessPoint.SECURITY_PSK) {
+            } else if (mAccessPoint.getSecurity() == AccessPoint.SECURITY_PSK) {
                 mSubmitButton.setEnabled(mPasswordView.length() >= 8);
             }
         } else {