Split WifiStateMachine from WifiStateTracker

Notifications handled in WifiService. WifiStateTracker tracks
state for connectivity service

Change-Id: Idb0cf494898d28712af0f95f9e60c5417cd4a053
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 11cd526..efbccd2 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -526,12 +526,6 @@
         return -1;
     }
 
-    /**
-     * This is not supported.
-     */
-    public void interpretScanResultsAvailable() {
-    }
-
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer("Mobile data state: ");
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 44215e7..82735e5 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -27,18 +27,17 @@
 public interface NetworkStateTracker {
 
     public static final int EVENT_STATE_CHANGED = 1;
-    public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2;
     /**
      * arg1: 1 to show, 0 to hide
      * arg2: ID of the notification
      * obj: Notification (if showing)
      */
-    public static final int EVENT_NOTIFICATION_CHANGED = 3;
-    public static final int EVENT_CONFIGURATION_CHANGED = 4;
-    public static final int EVENT_ROAMING_CHANGED = 5;
-    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6;
-    public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7;
-    public static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8;
+    public static final int EVENT_NOTIFICATION_CHANGED = 2;
+    public static final int EVENT_CONFIGURATION_CHANGED = 3;
+    public static final int EVENT_ROAMING_CHANGED = 4;
+    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 5;
+    public static final int EVENT_RESTORE_DEFAULT_NETWORK = 6;
+    public static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 7;
 
     /**
      * Fetch NetworkInfo for the network
@@ -147,10 +146,4 @@
      */
     public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid);
 
-    /**
-     * Interprets scan results. This will be called at a safe time for
-     * processing, and from a safe thread.
-     */
-    public void interpretScanResultsAvailable();
-
 }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index cc1566b..ae4e168 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -314,14 +314,14 @@
             case ConnectivityManager.TYPE_WIFI:
                 if (DBG) Slog.v(TAG, "Starting Wifi Service.");
                 WifiStateTracker wst = new WifiStateTracker(context, mHandler);
-                WifiService wifiService = new WifiService(context, wst);
+                WifiService wifiService = new WifiService(context);
                 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
-                wifiService.startWifi();
+                wifiService.checkAndStartWifi();
                 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
                 wst.startMonitoring();
 
                 //TODO: as part of WWS refactor, create only when needed
-                mWifiWatchdogService = new WifiWatchdogService(context, wst);
+                mWifiWatchdogService = new WifiWatchdogService(context);
 
                 break;
             case ConnectivityManager.TYPE_MOBILE:
@@ -1205,16 +1205,6 @@
         sendConnectedBroadcast(info);
     }
 
-    private void handleScanResultsAvailable(NetworkInfo info) {
-        int networkType = info.getType();
-        if (networkType != ConnectivityManager.TYPE_WIFI) {
-            if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " +
-                    info.getTypeName() + " network. Don't know how to handle.");
-        }
-
-        mNetTrackers[networkType].interpretScanResultsAvailable();
-    }
-
     private void handleNotificationChange(boolean visible, int id,
             Notification notification) {
         NotificationManager notificationManager = (NotificationManager) mContext
@@ -1619,11 +1609,6 @@
                     }
                     break;
 
-                case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
-                    info = (NetworkInfo) msg.obj;
-                    handleScanResultsAvailable(info);
-                    break;
-
                 case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
                     handleNotificationChange(msg.arg1 == 1, msg.arg2,
                             (Notification) msg.obj);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 15080b2..b43b33e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -17,6 +17,8 @@
 package com.android.server;
 
 import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothDevice;
@@ -26,25 +28,30 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.database.ContentObserver;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.net.wifi.WifiStateTracker;
+import android.net.wifi.WifiStateMachine;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.ConnectivityManager;
 import android.net.InterfaceConfiguration;
-import android.net.NetworkStateTracker;
 import android.net.DhcpInfo;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import java.util.ArrayList;
@@ -72,7 +79,7 @@
     private static final String TAG = "WifiService";
     private static final boolean DBG = true;
 
-    private final WifiStateTracker mWifiStateTracker;
+    private final WifiStateMachine mWifiStateMachine;
 
     private Context mContext;
 
@@ -123,10 +130,63 @@
 
     private boolean mIsReceiverRegistered = false;
 
-    WifiService(Context context, WifiStateTracker tracker) {
+
+    NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
+
+    // Variables relating to the 'available networks' notification
+    /**
+     * The icon to show in the 'available networks' notification. This will also
+     * be the ID of the Notification given to the NotificationManager.
+     */
+    private static final int ICON_NETWORKS_AVAILABLE =
+            com.android.internal.R.drawable.stat_notify_wifi_in_range;
+    /**
+     * When a notification is shown, we wait this amount before possibly showing it again.
+     */
+    private final long NOTIFICATION_REPEAT_DELAY_MS;
+    /**
+     * Whether the user has set the setting to show the 'available networks' notification.
+     */
+    private boolean mNotificationEnabled;
+    /**
+     * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
+     */
+    private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
+    /**
+     * The {@link System#currentTimeMillis()} must be at least this value for us
+     * to show the notification again.
+     */
+    private long mNotificationRepeatTime;
+    /**
+     * The Notification object given to the NotificationManager.
+     */
+    private Notification mNotification;
+    /**
+     * Whether the notification is being shown, as set by us. That is, if the
+     * user cancels the notification, we will not receive the callback so this
+     * will still be true. We only guarantee if this is false, then the
+     * notification is not showing.
+     */
+    private boolean mNotificationShown;
+    /**
+     * The number of continuous scans that must occur before consider the
+     * supplicant in a scanning state. This allows supplicant to associate with
+     * remembered networks that are in the scan results.
+     */
+    private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
+    /**
+     * The number of scans since the last network state change. When this
+     * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
+     * supplicant to actually be scanning. When the network state changes to
+     * something other than scanning, we reset this to 0.
+     */
+    private int mNumScansSinceNetworkStateChange;
+
+
+    WifiService(Context context) {
         mContext = context;
-        mWifiStateTracker = tracker;
-        mWifiStateTracker.enableRssiPolling(true);
+        mWifiStateMachine = new WifiStateMachine(mContext);
+        mWifiStateMachine.enableRssiPolling(true);
         mBatteryStats = BatteryStatsService.getService();
 
         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
@@ -164,6 +224,42 @@
 
                 }
             },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+
+        mContext.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+                            // reset & clear notification on any wifi state change
+                            resetNotification();
+                        } else if (intent.getAction().equals(
+                                WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+                                    WifiManager.EXTRA_NETWORK_INFO);
+                            // reset & clear notification on a network connect & disconnect
+                            switch(mNetworkInfo.getDetailedState()) {
+                                case CONNECTED:
+                                case DISCONNECTED:
+                                    resetNotification();
+                                    break;
+                            }
+                        } else if (intent.getAction().equals(
+                                WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+                            checkAndSetNotification();
+                        }
+                    }
+                }, filter);
+
+        // Setting is in seconds
+        NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
+        mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler());
+        mNotificationEnabledSettingObserver.register();
     }
 
     /**
@@ -172,7 +268,7 @@
      *
      * This function is used only at boot time
      */
-    public void startWifi() {
+    public void checkAndStartWifi() {
         /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
         boolean wifiEnabled = !isAirplaneModeOn()
                 && (getPersistedWifiEnabled() || testAndClearWifiSavedState());
@@ -255,17 +351,13 @@
         Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
     }
 
-    NetworkStateTracker getNetworkStateTracker() {
-        return mWifiStateTracker;
-    }
-
     /**
      * see {@link android.net.wifi.WifiManager#pingSupplicant()}
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
     public boolean pingSupplicant() {
         enforceAccessPermission();
-        return mWifiStateTracker.pingSupplicant();
+        return mWifiStateMachine.pingSupplicant();
     }
 
     /**
@@ -274,7 +366,7 @@
      */
     public boolean startScan(boolean forceActive) {
         enforceChangePermission();
-        return mWifiStateTracker.startScan(forceActive);
+        return mWifiStateMachine.startScan(forceActive);
     }
 
     private void enforceAccessPermission() {
@@ -304,7 +396,7 @@
         enforceChangePermission();
 
         if (DBG) {
-            Slog.e(TAG, "Invoking mWifiStateTracker.setWifiEnabled\n");
+            Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
         }
 
         // set a flag if the user is enabling Wifi while in airplane mode
@@ -312,7 +404,7 @@
             mAirplaneModeOverwridden.set(true);
         }
 
-        mWifiStateTracker.setWifiEnabled(enable);
+        mWifiStateMachine.setWifiEnabled(enable);
         persistWifiEnabled(enable);
 
         if (enable) {
@@ -338,7 +430,7 @@
      */
     public int getWifiEnabledState() {
         enforceAccessPermission();
-        return mWifiStateTracker.getWifiState();
+        return mWifiStateMachine.getWifiState();
     }
 
     /**
@@ -362,7 +454,7 @@
             setWifiApConfiguration(wifiConfig);
         }
 
-        mWifiStateTracker.setWifiApEnabled(wifiConfig, enabled);
+        mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
 
         return true;
     }
@@ -377,7 +469,7 @@
      */
     public int getWifiApEnabledState() {
         enforceAccessPermission();
-        return mWifiStateTracker.getWifiApState();
+        return mWifiStateMachine.getWifiApState();
     }
 
     /**
@@ -427,7 +519,7 @@
      */
     public boolean disconnect() {
         enforceChangePermission();
-        return mWifiStateTracker.disconnectCommand();
+        return mWifiStateMachine.disconnectCommand();
     }
 
     /**
@@ -436,7 +528,7 @@
      */
     public boolean reconnect() {
         enforceChangePermission();
-        return mWifiStateTracker.reconnectCommand();
+        return mWifiStateMachine.reconnectCommand();
     }
 
     /**
@@ -445,7 +537,7 @@
      */
     public boolean reassociate() {
         enforceChangePermission();
-        return mWifiStateTracker.reassociateCommand();
+        return mWifiStateMachine.reassociateCommand();
     }
 
     /**
@@ -454,7 +546,7 @@
      */
     public List<WifiConfiguration> getConfiguredNetworks() {
         enforceAccessPermission();
-        return mWifiStateTracker.getConfiguredNetworks();
+        return mWifiStateMachine.getConfiguredNetworks();
     }
 
     /**
@@ -464,7 +556,7 @@
      */
     public int addOrUpdateNetwork(WifiConfiguration config) {
         enforceChangePermission();
-        return mWifiStateTracker.addOrUpdateNetwork(config);
+        return mWifiStateMachine.addOrUpdateNetwork(config);
     }
 
      /**
@@ -475,7 +567,7 @@
      */
     public boolean removeNetwork(int netId) {
         enforceChangePermission();
-        return mWifiStateTracker.removeNetwork(netId);
+        return mWifiStateMachine.removeNetwork(netId);
     }
 
     /**
@@ -487,7 +579,7 @@
      */
     public boolean enableNetwork(int netId, boolean disableOthers) {
         enforceChangePermission();
-        return mWifiStateTracker.enableNetwork(netId, disableOthers);
+        return mWifiStateMachine.enableNetwork(netId, disableOthers);
     }
 
     /**
@@ -498,7 +590,7 @@
      */
     public boolean disableNetwork(int netId) {
         enforceChangePermission();
-        return mWifiStateTracker.disableNetwork(netId);
+        return mWifiStateMachine.disableNetwork(netId);
     }
 
     /**
@@ -511,7 +603,7 @@
          * Make sure we have the latest information, by sending
          * a status request to the supplicant.
          */
-        return mWifiStateTracker.requestConnectionInfo();
+        return mWifiStateMachine.requestConnectionInfo();
     }
 
     /**
@@ -521,7 +613,7 @@
      */
     public List<ScanResult> getScanResults() {
         enforceAccessPermission();
-        return mWifiStateTracker.getScanResultsList();
+        return mWifiStateMachine.getScanResultsList();
     }
 
     /**
@@ -533,7 +625,7 @@
     public boolean saveConfiguration() {
         boolean result = true;
         enforceChangePermission();
-        return mWifiStateTracker.saveConfig();
+        return mWifiStateMachine.saveConfig();
     }
 
     /**
@@ -576,7 +668,7 @@
                     numChannels);
         }
 
-        mWifiStateTracker.setNumAllowedChannels(numChannels);
+        mWifiStateMachine.setNumAllowedChannels(numChannels);
 
         return true;
     }
@@ -596,7 +688,7 @@
          * Wi-Fi is not currently enabled), get the value from
          * Settings.
          */
-        numChannels = mWifiStateTracker.getNumAllowedChannels();
+        numChannels = mWifiStateMachine.getNumAllowedChannels();
         if (numChannels < 0) {
             numChannels = Settings.Secure.getInt(mContext.getContentResolver(),
                     Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
@@ -622,9 +714,59 @@
      */
     public DhcpInfo getDhcpInfo() {
         enforceAccessPermission();
-        return mWifiStateTracker.getDhcpInfo();
+        return mWifiStateMachine.getDhcpInfo();
     }
 
+    /**
+     * see {@link android.net.wifi.WifiManager#startWifi}
+     *
+     */
+    public void startWifi() {
+        enforceChangePermission();
+        /* TODO: may be add permissions for access only to connectivity service
+         * TODO: if a start issued, keep wifi alive until a stop issued irrespective
+         * of WifiLock & device idle status unless wifi enabled status is toggled
+         */
+
+        mWifiStateMachine.setDriverStart(true);
+        mWifiStateMachine.reconnectCommand();
+    }
+
+    /**
+     * see {@link android.net.wifi.WifiManager#stopWifi}
+     *
+     */
+    public void stopWifi() {
+        enforceChangePermission();
+        /* TODO: may be add permissions for access only to connectivity service
+         * TODO: if a stop is issued, wifi is brought up only by startWifi
+         * unless wifi enabled status is toggled
+         */
+        mWifiStateMachine.setDriverStart(false);
+    }
+
+
+    /**
+     * see {@link android.net.wifi.WifiManager#addToBlacklist}
+     *
+     */
+    public void addToBlacklist(String bssid) {
+        enforceChangePermission();
+
+        mWifiStateMachine.addToBlacklist(bssid);
+    }
+
+    /**
+     * see {@link android.net.wifi.WifiManager#clearBlacklist}
+     *
+     */
+    public void clearBlacklist() {
+        enforceChangePermission();
+
+        mWifiStateMachine.clearBlacklist();
+    }
+
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -641,11 +783,11 @@
                 mAlarmManager.cancel(mIdleIntent);
                 mDeviceIdle = false;
                 mScreenOff = false;
-                mWifiStateTracker.enableRssiPolling(true);
+                mWifiStateMachine.enableRssiPolling(true);
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 Slog.d(TAG, "ACTION_SCREEN_OFF");
                 mScreenOff = true;
-                mWifiStateTracker.enableRssiPolling(false);
+                mWifiStateMachine.enableRssiPolling(false);
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                  * AND the "stay on while plugged in" setting doesn't match the
@@ -653,7 +795,7 @@
                  * or plugged in to AC).
                  */
                 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
-                    WifiInfo info = mWifiStateTracker.requestConnectionInfo();
+                    WifiInfo info = mWifiStateMachine.requestConnectionInfo();
                     if (info.getSupplicantState() != SupplicantState.COMPLETED) {
                         // we used to go to sleep immediately, but this caused some race conditions
                         // we don't have time to track down for this release.  Delay instead,
@@ -704,7 +846,7 @@
                         isBluetoothPlaying = true;
                     }
                 }
-                mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying);
+                mWifiStateMachine.setBluetoothScanMode(isBluetoothPlaying);
 
             } else {
                 return;
@@ -771,21 +913,21 @@
 
         /* Disable tethering when airplane mode is enabled */
         if (airplaneMode) {
-            mWifiStateTracker.setWifiApEnabled(null, false);
+            mWifiStateMachine.setWifiApEnabled(null, false);
         }
 
         if (wifiShouldBeEnabled) {
             if (wifiShouldBeStarted) {
-                mWifiStateTracker.setWifiEnabled(true);
-                mWifiStateTracker.setScanOnlyMode(
+                mWifiStateMachine.setWifiEnabled(true);
+                mWifiStateMachine.setScanOnlyMode(
                         strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
-                mWifiStateTracker.startWifi(true);
+                mWifiStateMachine.setDriverStart(true);
             } else {
-                mWifiStateTracker.requestCmWakeLock();
-                mWifiStateTracker.disconnectAndStop();
+                mWifiStateMachine.requestCmWakeLock();
+                mWifiStateMachine.setDriverStart(false);
             }
         } else {
-            mWifiStateTracker.setWifiEnabled(false);
+            mWifiStateMachine.setWifiEnabled(false);
         }
     }
 
@@ -832,17 +974,17 @@
                     + ", uid=" + Binder.getCallingUid());
             return;
         }
-        pw.println("Wi-Fi is " + mWifiStateTracker.getWifiStateByName());
+        pw.println("Wi-Fi is " + mWifiStateMachine.getWifiStateByName());
         pw.println("Stay-awake conditions: " +
                 Settings.System.getInt(mContext.getContentResolver(),
                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
         pw.println();
 
         pw.println("Internal state:");
-        pw.println(mWifiStateTracker);
+        pw.println(mWifiStateMachine);
         pw.println();
         pw.println("Latest scan results:");
-        List<ScanResult> scanResults = mWifiStateTracker.getScanResultsList();
+        List<ScanResult> scanResults = mWifiStateMachine.getScanResultsList();
         if (scanResults != null && scanResults.size() != 0) {
             pw.println("  BSSID              Frequency   RSSI  Flags             SSID");
             for (ScanResult r : scanResults) {
@@ -1069,7 +1211,7 @@
             if (mMulticasters.size() != 0) {
                 return;
             } else {
-                mWifiStateTracker.startPacketFiltering();
+                mWifiStateMachine.startPacketFiltering();
             }
         }
     }
@@ -1084,7 +1226,7 @@
             // our new size == 1 (first call), but this function won't
             // be called often and by making the stopPacket call each
             // time we're less fragile and self-healing.
-            mWifiStateTracker.stopPacketFiltering();
+            mWifiStateMachine.stopPacketFiltering();
         }
 
         int uid = Binder.getCallingUid();
@@ -1121,7 +1263,7 @@
             removed.unlinkDeathRecipient();
         }
         if (mMulticasters.size() == 0) {
-            mWifiStateTracker.startPacketFiltering();
+            mWifiStateMachine.startPacketFiltering();
         }
 
         Long ident = Binder.clearCallingIdentity();
@@ -1140,4 +1282,166 @@
             return (mMulticasters.size() > 0);
         }
     }
+
+    private void checkAndSetNotification() {
+        // If we shouldn't place a notification on available networks, then
+        // don't bother doing any of the following
+        if (!mNotificationEnabled) return;
+
+        State state = mNetworkInfo.getState();
+        if ((state == NetworkInfo.State.DISCONNECTED)
+                || (state == NetworkInfo.State.UNKNOWN)) {
+            // Look for an open network
+            List<ScanResult> scanResults = mWifiStateMachine.getScanResultsList();
+            if (scanResults != null) {
+                int numOpenNetworks = 0;
+                for (int i = scanResults.size() - 1; i >= 0; i--) {
+                    ScanResult scanResult = scanResults.get(i);
+
+                    if (TextUtils.isEmpty(scanResult.capabilities)) {
+                        numOpenNetworks++;
+                    }
+                }
+
+                if (numOpenNetworks > 0) {
+                    if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
+                        /*
+                         * We've scanned continuously at least
+                         * NUM_SCANS_BEFORE_NOTIFICATION times. The user
+                         * probably does not have a remembered network in range,
+                         * since otherwise supplicant would have tried to
+                         * associate and thus resetting this counter.
+                         */
+                        setNotificationVisible(true, numOpenNetworks, false, 0);
+                    }
+                    return;
+                }
+            }
+        }
+
+        // No open networks in range, remove the notification
+        setNotificationVisible(false, 0, false, 0);
+    }
+
+    /**
+     * Clears variables related to tracking whether a notification has been
+     * shown recently and clears the current notification.
+     */
+    private void resetNotification() {
+        mNotificationRepeatTime = 0;
+        mNumScansSinceNetworkStateChange = 0;
+        setNotificationVisible(false, 0, false, 0);
+    }
+
+    /**
+     * Display or don't display a notification that there are open Wi-Fi networks.
+     * @param visible {@code true} if notification should be visible, {@code false} otherwise
+     * @param numNetworks the number networks seen
+     * @param force {@code true} to force notification to be shown/not-shown,
+     * even if it is already shown/not-shown.
+     * @param delay time in milliseconds after which the notification should be made
+     * visible or invisible.
+     */
+    private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
+            int delay) {
+
+        // Since we use auto cancel on the notification, when the
+        // mNetworksAvailableNotificationShown is true, the notification may
+        // have actually been canceled.  However, when it is false we know
+        // for sure that it is not being shown (it will not be shown any other
+        // place than here)
+
+        // If it should be hidden and it is already hidden, then noop
+        if (!visible && !mNotificationShown && !force) {
+            return;
+        }
+
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+
+        Message message;
+        if (visible) {
+
+            // Not enough time has passed to show the notification again
+            if (System.currentTimeMillis() < mNotificationRepeatTime) {
+                return;
+            }
+
+            if (mNotification == null) {
+                // Cache the Notification mainly so we can remove the
+                // EVENT_NOTIFICATION_CHANGED message with this Notification from
+                // the queue later
+                mNotification = new Notification();
+                mNotification.when = 0;
+                mNotification.icon = ICON_NETWORKS_AVAILABLE;
+                mNotification.flags = Notification.FLAG_AUTO_CANCEL;
+                mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
+                        new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
+            }
+
+            CharSequence title = mContext.getResources().getQuantityText(
+                    com.android.internal.R.plurals.wifi_available, numNetworks);
+            CharSequence details = mContext.getResources().getQuantityText(
+                    com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
+            mNotification.tickerText = title;
+            mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
+
+            mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
+
+            notificationManager.notify(ICON_NETWORKS_AVAILABLE, mNotification);
+            /*
+             * TODO: Clean up connectivity service & remove this
+             */
+            /* message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 1,
+                    ICON_NETWORKS_AVAILABLE, mNotification); */
+
+
+        } else {
+
+            notificationManager.cancel(ICON_NETWORKS_AVAILABLE);
+            /*
+             * TODO: Clean up connectivity service & remove this
+             */
+            /*
+            // Remove any pending messages to show the notification
+            mCsHandler.removeMessages(EVENT_NOTIFICATION_CHANGED, mNotification);
+
+            message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 0,
+                    ICON_NETWORKS_AVAILABLE);
+             */
+        }
+
+        //mCsHandler.sendMessageDelayed(message, delay);
+
+        mNotificationShown = visible;
+    }
+
+    private class NotificationEnabledSettingObserver extends ContentObserver {
+
+        public NotificationEnabledSettingObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void register() {
+            ContentResolver cr = mContext.getContentResolver();
+            cr.registerContentObserver(Settings.Secure.getUriFor(
+                Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
+            mNotificationEnabled = getValue();
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+
+            mNotificationEnabled = getValue();
+            resetNotification();
+        }
+
+        private boolean getValue() {
+            return Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
+        }
+    }
+
+
 }
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index be14cd3..46d6bef 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -27,7 +27,6 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.net.wifi.WifiStateTracker;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -77,7 +76,6 @@
     
     private Context mContext;
     private ContentResolver mContentResolver;
-    private WifiStateTracker mWifiStateTracker;
     private WifiManager mWifiManager;
     
     /**
@@ -108,10 +106,9 @@
     /** Whether the current AP check should be canceled. */
     private boolean mShouldCancel;
     
-    WifiWatchdogService(Context context, WifiStateTracker wifiStateTracker) {
+    WifiWatchdogService(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
-        mWifiStateTracker = wifiStateTracker;
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
         
         createThread();
@@ -752,7 +749,7 @@
         // Black list this "bad" AP, this will cause an attempt to connect to another
         blacklistAp(ap.bssid);
         // Initiate an association to an alternate AP
-        mWifiStateTracker.reassociateCommand();
+        mWifiManager.reassociate();
     }
 
     private void blacklistAp(String bssid) {
@@ -763,7 +760,7 @@
         // Before taking action, make sure we should not cancel our processing
         if (shouldCancel()) return;
         
-        mWifiStateTracker.addToBlacklist(bssid);
+        mWifiManager.addToBlacklist(bssid);
 
         if (D) {
             myLogD("Blacklisting " + bssid);
@@ -858,7 +855,7 @@
              * (and blacklisted them). Clear the blacklist so the AP with best
              * signal is chosen.
              */
-            mWifiStateTracker.clearBlacklist();
+            mWifiManager.clearBlacklist();
             
             if (V) {
                 myLogV("handleSleep: Set state to SLEEP and cleared blacklist");
@@ -929,7 +926,7 @@
      * should revert anything done by the watchdog monitoring.
      */
     private void handleReset() {
-        mWifiStateTracker.clearBlacklist();
+        mWifiManager.clearBlacklist();
         setIdleState(true);
     }
     
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 6e0bc9d..3426af7 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -85,5 +85,13 @@
     WifiConfiguration getWifiApConfiguration();
 
     void setWifiApConfiguration(in WifiConfiguration wifiConfig);
+
+    void startWifi();
+
+    void stopWifi();
+
+    void addToBlacklist(String bssid);
+
+    void clearBlacklist();
 }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6fac902..339763a 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -293,6 +293,21 @@
     public static final String EXTRA_NEW_RSSI = "newRssi";
 
     /**
+     * Broadcast intent action indicating that the IP configuration
+     * changed on wifi.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String CONFIG_CHANGED_ACTION = "android.net.wifi.CONFIG_CHANGED";
+    /**
+     * The lookup key for a {@link android.net.NetworkProperties} object associated with the
+     * Wi-Fi network. Retrieve with
+     * {@link android.content.Intent#getParcelableExtra(String)}.
+     * @hide
+     */
+    public static final String EXTRA_NETWORK_PROPERTIES = "networkProperties";
+
+    /**
      * The network IDs of the configured networks could have changed.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -838,6 +853,82 @@
         }
     }
 
+   /**
+     * Start the driver and connect to network.
+     *
+     * This function will over-ride WifiLock and device idle status. For example,
+     * even if the device is idle or there is only a scan-only lock held,
+     * a start wifi would mean that wifi connection is kept active until
+     * a stopWifi() is sent.
+     *
+     * This API is used by WifiStateTracker
+     *
+     * @return {@code true} if the operation succeeds else {@code false}
+     * @hide
+     */
+    public boolean startWifi() {
+        try {
+            mService.startWifi();
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Disconnect from a network (if any) and stop the driver.
+     *
+     * This function will over-ride WifiLock and device idle status. Wi-Fi
+     * stays inactive until a startWifi() is issued.
+     *
+     * This API is used by WifiStateTracker
+     *
+     * @return {@code true} if the operation succeeds else {@code false}
+     * @hide
+     */
+    public boolean stopWifi() {
+        try {
+            mService.stopWifi();
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Add a bssid to the supplicant blacklist
+     *
+     * This API is used by WifiWatchdogService
+     *
+     * @return {@code true} if the operation succeeds else {@code false}
+     * @hide
+     */
+    public boolean addToBlacklist(String bssid) {
+        try {
+            mService.addToBlacklist(bssid);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Clear the supplicant blacklist
+     *
+     * This API is used by WifiWatchdogService
+     *
+     * @return {@code true} if the operation succeeds else {@code false}
+     * @hide
+     */
+    public boolean clearBlacklist() {
+        try {
+            mService.clearBlacklist();
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     /**
      * Allows an application to keep the Wi-Fi radio awake.
      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index f2f8343..af3132f 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -19,14 +19,13 @@
 import android.util.Log;
 import android.util.Config;
 import android.net.NetworkInfo;
-import android.net.NetworkStateTracker;
 
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
 /**
  * Listens for events from the wpa_supplicant server, and passes them on
- * to the {@link WifiStateTracker} for handling. Runs in its own thread.
+ * to the {@link WifiStateMachine} for handling. Runs in its own thread.
  *
  * @hide
  */
@@ -117,7 +116,7 @@
     private static Pattern mConnectedEventPattern =
         Pattern.compile("((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) .* \\[id=([0-9]+) ");
 
-    private final WifiStateTracker mWifiStateTracker;
+    private final WifiStateMachine mWifiStateMachine;
 
     /**
      * This indicates the supplicant connection for the monitor is closed
@@ -139,18 +138,14 @@
      */
     private static final int MAX_RECV_ERRORS    = 10;
 
-    public WifiMonitor(WifiStateTracker tracker) {
-        mWifiStateTracker = tracker;
+    public WifiMonitor(WifiStateMachine wifiStateMachine) {
+        mWifiStateMachine = wifiStateMachine;
     }
 
     public void startMonitoring() {
         new MonitorThread().start();
     }
 
-    public NetworkStateTracker getNetworkStateTracker() {
-        return mWifiStateTracker;
-    }
-
     class MonitorThread extends Thread {
         public MonitorThread() {
             super("WifiMonitor");
@@ -161,9 +156,9 @@
             if (connectToSupplicant()) {
                 // Send a message indicating that it is now possible to send commands
                 // to the supplicant
-                mWifiStateTracker.notifySupplicantConnection();
+                mWifiStateMachine.notifySupplicantConnection();
             } else {
-                mWifiStateTracker.notifySupplicantLost();
+                mWifiStateMachine.notifySupplicantLost();
                 return;
             }
 
@@ -259,7 +254,7 @@
                     }
 
                     // notify and exit
-                    mWifiStateTracker.notifySupplicantLost();
+                    mWifiStateMachine.notifySupplicantLost();
                     break;
                 } else {
                     handleEvent(event, eventData);
@@ -285,7 +280,7 @@
         }
 
         private void handlePasswordKeyMayBeIncorrect() {
-            mWifiStateTracker.notifyPasswordKeyMayBeIncorrect();
+            mWifiStateMachine.notifyPasswordKeyMayBeIncorrect();
         }
 
         private void handleDriverEvent(String state) {
@@ -293,11 +288,11 @@
                 return;
             }
             if (state.equals("STOPPED")) {
-                mWifiStateTracker.notifyDriverStopped();
+                mWifiStateMachine.notifyDriverStopped();
             } else if (state.equals("STARTED")) {
-                mWifiStateTracker.notifyDriverStarted();
+                mWifiStateMachine.notifyDriverStarted();
             } else if (state.equals("HANGED")) {
-                mWifiStateTracker.notifyDriverHung();
+                mWifiStateMachine.notifyDriverHung();
             }
         }
 
@@ -318,7 +313,7 @@
                     break;
 
                 case SCAN_RESULTS:
-                    mWifiStateTracker.notifyScanResultsAvailable();
+                    mWifiStateMachine.notifyScanResultsAvailable();
                     break;
 
                 case UNKNOWN:
@@ -375,7 +370,7 @@
             if (newSupplicantState == SupplicantState.INVALID) {
                 Log.w(TAG, "Invalid supplicant state: " + newState);
             }
-            mWifiStateTracker.notifySupplicantStateChange(networkId, BSSID, newSupplicantState);
+            mWifiStateMachine.notifySupplicantStateChange(networkId, BSSID, newSupplicantState);
         }
     }
 
@@ -395,7 +390,7 @@
                 }
             }
         }
-        mWifiStateTracker.notifyNetworkStateChange(newState, BSSID, networkId);
+        mWifiStateMachine.notifyNetworkStateChange(newState, BSSID, networkId);
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
new file mode 100644
index 0000000..6794c05
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -0,0 +1,3572 @@
+/*
+ * 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 android.net.wifi;
+
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+
+/**
+ * TODO: Add soft AP states as part of WIFI_STATE_XXX
+ * Retain WIFI_STATE_ENABLING that indicates driver is loading
+ * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
+ * and WIFI_STATE_FAILED for failure
+ * Deprecate WIFI_STATE_UNKNOWN
+ *
+ * Doing this will simplify the logic for sending broadcasts
+ */
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+
+import android.app.ActivityManagerNative;
+import android.net.NetworkInfo;
+import android.net.DhcpInfo;
+import android.net.NetworkUtils;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkProperties;
+import android.os.Binder;
+import android.os.Message;
+import android.os.Parcelable;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.PowerManager;
+import android.os.SystemProperties;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.Process;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+import android.app.backup.IBackupManager;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothA2dp;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.Context;
+import android.database.ContentObserver;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.HierarchicalState;
+import com.android.internal.util.HierarchicalStateMachine;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
+
+/**
+ * Track the state of Wifi connectivity. All event handling is done here,
+ * and all changes in connectivity state are initiated here.
+ *
+ * @hide
+ */
+//TODO: we still need frequent scanning for the case when
+// we issue disconnect but need scan results for open network notification
+public class WifiStateMachine extends HierarchicalStateMachine {
+
+    private static final String TAG = "WifiStateMachine";
+    private static final String NETWORKTYPE = "WIFI";
+    private static final boolean DBG = false;
+
+    /* TODO: fetch a configurable interface */
+    private static final String SOFTAP_IFACE = "wl0.1";
+
+    private WifiMonitor mWifiMonitor;
+    private INetworkManagementService nwService;
+    private ConnectivityManager mCm;
+
+    /* Scan results handling */
+    private List<ScanResult> mScanResults;
+    private static final Pattern scanResultPattern = Pattern.compile("\t+");
+    private static final int SCAN_RESULT_CACHE_SIZE = 80;
+    private final LinkedHashMap<String, ScanResult> mScanResultCache;
+
+    private String mInterfaceName;
+
+    private int mNumAllowedChannels = 0;
+    private int mLastSignalLevel = -1;
+    private String mLastBssid;
+    private int mLastNetworkId;
+    private boolean mEnableRssiPolling = false;
+    private boolean mPasswordKeyMayBeIncorrect = false;
+    private boolean mUseStaticIp = false;
+    private int mReconnectCount = 0;
+    private boolean mIsScanMode = false;
+    private boolean mConfigChanged = false;
+
+    /**
+     * Instance of the bluetooth headset helper. This needs to be created
+     * early because there is a delay before it actually 'connects', as
+     * noted by its javadoc. If we check before it is connected, it will be
+     * in an error state and we will not disable coexistence.
+     */
+    private BluetoothHeadset mBluetoothHeadset;
+
+    private BluetoothA2dp mBluetoothA2dp;
+
+    /**
+     * Observes the static IP address settings.
+     */
+    private SettingsObserver mSettingsObserver;
+    private NetworkProperties mNetworkProperties;
+
+    // Held during driver load and unload
+    private static PowerManager.WakeLock sWakeLock;
+
+    private Context mContext;
+
+    private DhcpInfo mDhcpInfo;
+    private WifiInfo mWifiInfo;
+    private NetworkInfo mNetworkInfo;
+    private SupplicantStateTracker mSupplicantStateTracker;
+
+    // Event log tags (must be in sync with event-log-tags)
+    private static final int EVENTLOG_WIFI_STATE_CHANGED        = 50021;
+    private static final int EVENTLOG_WIFI_EVENT_HANDLED        = 50022;
+    private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED  = 50023;
+
+    /* Load the driver */
+    private static final int CMD_LOAD_DRIVER                      = 1;
+    /* Unload the driver */
+    private static final int CMD_UNLOAD_DRIVER                    = 2;
+    /* Indicates driver load succeeded */
+    private static final int CMD_LOAD_DRIVER_SUCCESS              = 3;
+    /* Indicates driver load failed */
+    private static final int CMD_LOAD_DRIVER_FAILURE              = 4;
+    /* Indicates driver unload succeeded */
+    private static final int CMD_UNLOAD_DRIVER_SUCCESS            = 5;
+    /* Indicates driver unload failed */
+    private static final int CMD_UNLOAD_DRIVER_FAILURE            = 6;
+
+    /* Start the supplicant */
+    private static final int CMD_START_SUPPLICANT                 = 11;
+    /* Stop the supplicant */
+    private static final int CMD_STOP_SUPPLICANT                  = 12;
+    /* Start the driver */
+    private static final int CMD_START_DRIVER                     = 13;
+    /* Start the driver */
+    private static final int CMD_STOP_DRIVER                      = 14;
+    /* Indicates DHCP succeded */
+    private static final int CMD_IP_CONFIG_SUCCESS                = 15;
+    /* Indicates DHCP failed */
+    private static final int CMD_IP_CONFIG_FAILURE                = 16;
+    /* Re-configure interface */
+    private static final int CMD_RECONFIGURE_IP                   = 17;
+
+
+    /* Start the soft access point */
+    private static final int CMD_START_AP                         = 21;
+    /* Stop the soft access point */
+    private static final int CMD_STOP_AP                          = 22;
+
+
+    /* Supplicant events */
+    /* Connection to supplicant established */
+    private static final int SUP_CONNECTION_EVENT                 = 31;
+    /* Connection to supplicant lost */
+    private static final int SUP_DISCONNECTION_EVENT              = 32;
+    /* Driver start completed */
+    private static final int DRIVER_START_EVENT                   = 33;
+    /* Driver stop completed */
+    private static final int DRIVER_STOP_EVENT                    = 34;
+    /* Network connection completed */
+    private static final int NETWORK_CONNECTION_EVENT             = 36;
+    /* Network disconnection completed */
+    private static final int NETWORK_DISCONNECTION_EVENT          = 37;
+    /* Scan results are available */
+    private static final int SCAN_RESULTS_EVENT                   = 38;
+    /* Supplicate state changed */
+    private static final int SUPPLICANT_STATE_CHANGE_EVENT        = 39;
+    /* Password may be incorrect */
+    private static final int PASSWORD_MAY_BE_INCORRECT_EVENT      = 40;
+
+    /* Supplicant commands */
+    /* Is supplicant alive ? */
+    private static final int CMD_PING_SUPPLICANT                  = 51;
+    /* Add/update a network configuration */
+    private static final int CMD_ADD_OR_UPDATE_NETWORK            = 52;
+    /* Delete a network */
+    private static final int CMD_REMOVE_NETWORK                   = 53;
+    /* Enable a network. The device will attempt a connection to the given network. */
+    private static final int CMD_ENABLE_NETWORK                   = 54;
+    /* Disable a network. The device does not attempt a connection to the given network. */
+    private static final int CMD_DISABLE_NETWORK                  = 55;
+    /* Blacklist network. De-prioritizes the given BSSID for connection. */
+    private static final int CMD_BLACKLIST_NETWORK                = 56;
+    /* Clear the blacklist network list */
+    private static final int CMD_CLEAR_BLACKLIST                  = 57;
+    /* Get the configured networks */
+    private static final int CMD_GET_NETWORK_CONFIG               = 58;
+    /* Save configuration */
+    private static final int CMD_SAVE_CONFIG                      = 59;
+    /* Connection status */
+    private static final int CMD_CONNECTION_STATUS                = 60;
+
+    /* Supplicant commands after driver start*/
+    /* Initiate a scan */
+    private static final int CMD_START_SCAN                       = 71;
+    /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
+    private static final int CMD_SET_SCAN_MODE                    = 72;
+    /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
+    private static final int CMD_SET_SCAN_TYPE                    = 73;
+    /* Disconnect from a network */
+    private static final int CMD_DISCONNECT                       = 74;
+    /* Reconnect to a network */
+    private static final int CMD_RECONNECT                        = 75;
+    /* Reassociate to a network */
+    private static final int CMD_REASSOCIATE                      = 76;
+    /* Set power mode
+     * POWER_MODE_ACTIVE
+     * POWER_MODE_AUTO
+     */
+    private static final int CMD_SET_POWER_MODE                   = 77;
+    /* Set bluetooth co-existence
+     * BLUETOOTH_COEXISTENCE_MODE_ENABLED
+     * BLUETOOTH_COEXISTENCE_MODE_DISABLED
+     * BLUETOOTH_COEXISTENCE_MODE_SENSE
+     */
+    private static final int CMD_SET_BLUETOOTH_COEXISTENCE        = 78;
+    /* Enable/disable bluetooth scan mode
+     * true(1)
+     * false(0)
+     */
+    private static final int CMD_SET_BLUETOOTH_SCAN_MODE          = 79;
+    /* Set number of allowed channels */
+    private static final int CMD_SET_NUM_ALLOWED_CHANNELS         = 80;
+    /* Request connectivity manager wake lock before driver stop */
+    private static final int CMD_REQUEST_CM_WAKELOCK              = 81;
+    /* Enables RSSI poll */
+    private static final int CMD_ENABLE_RSSI_POLL                 = 82;
+    /* RSSI poll */
+    private static final int CMD_RSSI_POLL                        = 83;
+    /* Get current RSSI */
+    private static final int CMD_GET_RSSI                         = 84;
+    /* Get approx current RSSI */
+    private static final int CMD_GET_RSSI_APPROX                  = 85;
+    /* Get link speed on connection */
+    private static final int CMD_GET_LINK_SPEED                   = 86;
+    /* Radio mac address */
+    private static final int CMD_GET_MAC_ADDR                     = 87;
+    /* Set up packet filtering */
+    private static final int CMD_START_PACKET_FILTERING           = 88;
+    /* Clear packet filter */
+    private static final int CMD_STOP_PACKET_FILTERING            = 89;
+
+    /**
+     * Interval in milliseconds between polling for connection
+     * status items that are not sent via asynchronous events.
+     * An example is RSSI (signal strength).
+     */
+    private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
+
+    private static final int CONNECT_MODE   = 1;
+    private static final int SCAN_ONLY_MODE = 2;
+
+    private static final int SCAN_ACTIVE = 1;
+    private static final int SCAN_PASSIVE = 2;
+
+    /**
+     * The maximum number of times we will retry a connection to an access point
+     * for which we have failed in acquiring an IP address from DHCP. A value of
+     * N means that we will make N+1 connection attempts in all.
+     * <p>
+     * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
+     * value if a Settings value is not present.
+     */
+    private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
+
+    private static final int DRIVER_POWER_MODE_ACTIVE = 1;
+    private static final int DRIVER_POWER_MODE_AUTO = 0;
+
+    /* Default parent state */
+    private HierarchicalState mDefaultState = new DefaultState();
+    /* Temporary initial state */
+    private HierarchicalState mInitialState = new InitialState();
+    /* Unloading the driver */
+    private HierarchicalState mDriverUnloadingState = new DriverUnloadingState();
+    /* Loading the driver */
+    private HierarchicalState mDriverUnloadedState = new DriverUnloadedState();
+    /* Driver load/unload failed */
+    private HierarchicalState mDriverFailedState = new DriverFailedState();
+    /* Driver loading */
+    private HierarchicalState mDriverLoadingState = new DriverLoadingState();
+    /* Driver loaded */
+    private HierarchicalState mDriverLoadedState = new DriverLoadedState();
+    /* Driver loaded, waiting for supplicant to start */
+    private HierarchicalState mWaitForSupState = new WaitForSupState();
+
+    /* Driver loaded and supplicant ready */
+    private HierarchicalState mDriverSupReadyState = new DriverSupReadyState();
+    /* Driver start issued, waiting for completed event */
+    private HierarchicalState mDriverStartingState = new DriverStartingState();
+    /* Driver started */
+    private HierarchicalState mDriverStartedState = new DriverStartedState();
+    /* Driver stopping */
+    private HierarchicalState mDriverStoppingState = new DriverStoppingState();
+    /* Driver stopped */
+    private HierarchicalState mDriverStoppedState = new DriverStoppedState();
+    /* Scan for networks, no connection will be established */
+    private HierarchicalState mScanModeState = new ScanModeState();
+    /* Connecting to an access point */
+    private HierarchicalState mConnectModeState = new ConnectModeState();
+    /* Fetching IP after network connection (assoc+auth complete) */
+    private HierarchicalState mConnectingState = new ConnectingState();
+    /* Connected with IP addr */
+    private HierarchicalState mConnectedState = new ConnectedState();
+    /* disconnect issued, waiting for network disconnect confirmation */
+    private HierarchicalState mDisconnectingState = new DisconnectingState();
+    /* Network is not connected, supplicant assoc+auth is not complete */
+    private HierarchicalState mDisconnectedState = new DisconnectedState();
+
+    /* Soft Ap is running */
+    private HierarchicalState mSoftApStartedState = new SoftApStartedState();
+
+    /* Argument for Message object to indicate a synchronous call */
+    private static final int SYNCHRONOUS_CALL = 1;
+    private static final int ASYNCHRONOUS_CALL = 0;
+
+
+    /**
+     * One of  {@link WifiManager#WIFI_STATE_DISABLED},
+     *         {@link WifiManager#WIFI_STATE_DISABLING},
+     *         {@link WifiManager#WIFI_STATE_ENABLED},
+     *         {@link WifiManager#WIFI_STATE_ENABLING},
+     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
+     *
+     */
+    private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
+
+    /**
+     * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
+     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
+     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
+     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
+     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
+     *
+     */
+    private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
+
+    private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
+    private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
+
+    private final IBatteryStats mBatteryStats;
+
+    public WifiStateMachine(Context context) {
+        super(TAG);
+
+        mContext = context;
+
+        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
+        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
+
+        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+        nwService = INetworkManagementService.Stub.asInterface(b);
+
+        mWifiMonitor = new WifiMonitor(this);
+        mDhcpInfo = new DhcpInfo();
+        mWifiInfo = new WifiInfo();
+        mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0");
+        mSupplicantStateTracker = new SupplicantStateTracker(context, getHandler());
+
+        mBluetoothHeadset = new BluetoothHeadset(mContext, null);
+        mNetworkProperties = new NetworkProperties();
+
+        mNetworkInfo.setIsAvailable(false);
+        mNetworkProperties.clear();
+        mLastBssid = null;
+        mLastNetworkId = -1;
+        mLastSignalLevel = -1;
+
+        mScanResultCache = new LinkedHashMap<String, ScanResult>(
+            SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
+                /*
+                 * Limit the cache size by SCAN_RESULT_CACHE_SIZE
+                 * elements
+                 */
+                @Override
+                public boolean removeEldestEntry(Map.Entry eldest) {
+                    return SCAN_RESULT_CACHE_SIZE < this.size();
+                }
+        };
+
+        mSettingsObserver = new SettingsObserver(new Handler());
+
+        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+        addState(mDefaultState);
+            addState(mInitialState, mDefaultState);
+            addState(mDriverUnloadingState, mDefaultState);
+            addState(mDriverUnloadedState, mDefaultState);
+                addState(mDriverFailedState, mDriverUnloadedState);
+            addState(mDriverLoadingState, mDefaultState);
+            addState(mDriverLoadedState, mDefaultState);
+                addState(mWaitForSupState, mDriverLoadedState);
+            addState(mDriverSupReadyState, mDefaultState);
+                addState(mDriverStartingState, mDriverSupReadyState);
+                addState(mDriverStartedState, mDriverSupReadyState);
+                    addState(mScanModeState, mDriverStartedState);
+                    addState(mConnectModeState, mDriverStartedState);
+                        addState(mConnectingState, mConnectModeState);
+                        addState(mConnectedState, mConnectModeState);
+                        addState(mDisconnectingState, mConnectModeState);
+                        addState(mDisconnectedState, mConnectModeState);
+                addState(mDriverStoppingState, mDriverSupReadyState);
+                addState(mDriverStoppedState, mDriverSupReadyState);
+            addState(mSoftApStartedState, mDefaultState);
+
+        setInitialState(mInitialState);
+
+        if (DBG) setDbg(true);
+
+        //start the state machine
+        start();
+    }
+
+    /*********************************************************
+     * Methods exposed for public use
+     ********************************************************/
+
+    /**
+     * TODO: doc
+     */
+    public boolean pingSupplicant() {
+        return sendSyncMessage(CMD_PING_SUPPLICANT).boolValue;
+    }
+
+    /**
+     * TODO: doc
+     */
+    public boolean startScan(boolean forceActive) {
+        return sendSyncMessage(obtainMessage(CMD_START_SCAN, forceActive ?
+                SCAN_ACTIVE : SCAN_PASSIVE, 0)).boolValue;
+    }
+
+    /**
+     * TODO: doc
+     */
+    public void setWifiEnabled(boolean enable) {
+        mLastEnableUid.set(Binder.getCallingUid());
+        if (enable) {
+            /* Argument is the state that is entered prior to load */
+            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
+            sendMessage(CMD_START_SUPPLICANT);
+        } else {
+            sendMessage(CMD_STOP_SUPPLICANT);
+            /* Argument is the state that is entered upon success */
+            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
+        }
+    }
+
+    /**
+     * TODO: doc
+     */
+    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
+        mLastApEnableUid.set(Binder.getCallingUid());
+        if (enable) {
+            /* Argument is the state that is entered prior to load */
+            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
+            sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
+        } else {
+            sendMessage(CMD_STOP_AP);
+            /* Argument is the state that is entered upon success */
+            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
+        }
+    }
+
+    /**
+     * TODO: doc
+     */
+    public int getWifiState() {
+        return mWifiState.get();
+    }
+
+    /**
+     * TODO: doc
+     */
+    public String getWifiStateByName() {
+        switch (mWifiState.get()) {
+            case WIFI_STATE_DISABLING:
+                return "disabling";
+            case WIFI_STATE_DISABLED:
+                return "disabled";
+            case WIFI_STATE_ENABLING:
+                return "enabling";
+            case WIFI_STATE_ENABLED:
+                return "enabled";
+            case WIFI_STATE_UNKNOWN:
+                return "unknown state";
+            default:
+                return "[invalid state]";
+        }
+    }
+
+    /**
+     * TODO: doc
+     */
+    public int getWifiApState() {
+        return mWifiApState.get();
+    }
+
+    /**
+     * TODO: doc
+     */
+    public String getWifiApStateByName() {
+        switch (mWifiApState.get()) {
+            case WIFI_AP_STATE_DISABLING:
+                return "disabling";
+            case WIFI_AP_STATE_DISABLED:
+                return "disabled";
+            case WIFI_AP_STATE_ENABLING:
+                return "enabling";
+            case WIFI_AP_STATE_ENABLED:
+                return "enabled";
+            case WIFI_AP_STATE_FAILED:
+                return "failed";
+            default:
+                return "[invalid state]";
+        }
+    }
+
+    /**
+     * Get status information for the current connection, if any.
+     * @return a {@link WifiInfo} object containing information about the current connection
+     *
+     */
+    public WifiInfo requestConnectionInfo() {
+        return mWifiInfo;
+    }
+
+    public DhcpInfo getDhcpInfo() {
+        return mDhcpInfo;
+    }
+
+    /**
+     * TODO: doc
+     */
+    public void setDriverStart(boolean enable) {
+      if (enable) {
+          sendMessage(CMD_START_DRIVER);
+      } else {
+          sendMessage(CMD_STOP_DRIVER);
+      }
+    }
+
+    /**
+     * TODO: doc
+     */
+    public void setScanOnlyMode(boolean enable) {
+      if (enable) {
+          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
+      } else {
+          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
+      }
+    }
+
+    /**
+     * TODO: doc
+     */
+    public void setScanType(boolean active) {
+      if (active) {
+          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
+      } else {
+          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
+      }
+    }
+
+    /**
+     * TODO: doc
+     */
+    public List<ScanResult> getScanResultsList() {
+        return mScanResults;
+    }
+
+    /**
+     * Disconnect from Access Point
+     */
+    public boolean disconnectCommand() {
+        return sendSyncMessage(CMD_DISCONNECT).boolValue;
+    }
+
+    /**
+     * Initiate a reconnection to AP
+     */
+    public boolean reconnectCommand() {
+        return sendSyncMessage(CMD_RECONNECT).boolValue;
+    }
+
+    /**
+     * Initiate a re-association to AP
+     */
+    public boolean reassociateCommand() {
+        return sendSyncMessage(CMD_REASSOCIATE).boolValue;
+    }
+
+    /**
+     * Add a network synchronously
+     *
+     * @return network id of the new network
+     */
+    public int addOrUpdateNetwork(WifiConfiguration config) {
+        return sendSyncMessage(CMD_ADD_OR_UPDATE_NETWORK, config).intValue;
+    }
+
+    public List<WifiConfiguration> getConfiguredNetworks() {
+        return sendSyncMessage(CMD_GET_NETWORK_CONFIG).configList;
+    }
+
+    /**
+     * Delete a network
+     *
+     * @param networkId id of the network to be removed
+     */
+    public boolean removeNetwork(int networkId) {
+        return sendSyncMessage(obtainMessage(CMD_REMOVE_NETWORK, networkId, 0)).boolValue;
+    }
+
+    private class EnableNetParams {
+        private int netId;
+        private boolean disableOthers;
+        EnableNetParams(int n, boolean b) {
+            netId = n;
+            disableOthers = b;
+        }
+    }
+    /**
+     * Enable a network
+     *
+     * @param netId network id of the network
+     * @param disableOthers true, if all other networks have to be disabled
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public boolean enableNetwork(int netId, boolean disableOthers) {
+        return sendSyncMessage(CMD_ENABLE_NETWORK,
+                new EnableNetParams(netId, disableOthers)).boolValue;
+    }
+
+    /**
+     * Disable a network
+     *
+     * @param netId network id of the network
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public boolean disableNetwork(int netId) {
+        return sendSyncMessage(obtainMessage(CMD_DISABLE_NETWORK, netId, 0)).boolValue;
+    }
+
+    /**
+     * Blacklist a BSSID. This will avoid the AP if there are
+     * alternate APs to connect
+     *
+     * @param bssid BSSID of the network
+     */
+    public void addToBlacklist(String bssid) {
+        sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
+    }
+
+    /**
+     * Clear the blacklist list
+     *
+     */
+    public void clearBlacklist() {
+        sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
+    }
+
+    /**
+     * Get detailed status of the connection
+     *
+     * @return Example status result
+     *  bssid=aa:bb:cc:dd:ee:ff
+     *  ssid=TestNet
+     *  id=3
+     *  pairwise_cipher=NONE
+     *  group_cipher=NONE
+     *  key_mgmt=NONE
+     *  wpa_state=COMPLETED
+     *  ip_address=X.X.X.X
+     */
+    public String status() {
+        return sendSyncMessage(CMD_CONNECTION_STATUS).stringValue;
+    }
+
+    public void enableRssiPolling(boolean enabled) {
+       sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
+    }
+    /**
+     * Get RSSI to currently connected network
+     *
+     * @return RSSI value, -1 on failure
+     */
+    public int getRssi() {
+        return sendSyncMessage(CMD_GET_RSSI).intValue;
+    }
+
+    /**
+     * Get approx RSSI to currently connected network
+     *
+     * @return RSSI value, -1 on failure
+     */
+    public int getRssiApprox() {
+        return sendSyncMessage(CMD_GET_RSSI_APPROX).intValue;
+    }
+
+    /**
+     * Get link speed to currently connected network
+     *
+     * @return link speed, -1 on failure
+     */
+    public int getLinkSpeed() {
+        return sendSyncMessage(CMD_GET_LINK_SPEED).intValue;
+    }
+
+    /**
+     * Get MAC address of radio
+     *
+     * @return MAC address, null on failure
+     */
+    public String getMacAddress() {
+        return sendSyncMessage(CMD_GET_MAC_ADDR).stringValue;
+    }
+
+    /**
+     * Start packet filtering
+     */
+    public void startPacketFiltering() {
+        sendMessage(CMD_START_PACKET_FILTERING);
+    }
+
+    /**
+     * Stop packet filtering
+     */
+    public void stopPacketFiltering() {
+        sendMessage(CMD_STOP_PACKET_FILTERING);
+    }
+
+    /**
+     * Set power mode
+     * @param mode
+     *     DRIVER_POWER_MODE_AUTO
+     *     DRIVER_POWER_MODE_ACTIVE
+     */
+    public void setPowerMode(int mode) {
+        sendMessage(obtainMessage(CMD_SET_POWER_MODE, mode, 0));
+    }
+
+    /**
+     * Set the number of allowed radio frequency channels from the system
+     * setting value, if any.
+     */
+    public void setNumAllowedChannels() {
+        try {
+            setNumAllowedChannels(
+                    Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
+        } catch (Settings.SettingNotFoundException e) {
+            if (mNumAllowedChannels != 0) {
+                setNumAllowedChannels(mNumAllowedChannels);
+            }
+            // otherwise, use the driver default
+        }
+    }
+
+    /**
+     * Set the number of radio frequency channels that are allowed to be used
+     * in the current regulatory domain.
+     * @param numChannels the number of allowed channels. Must be greater than 0
+     * and less than or equal to 16.
+     */
+    public void setNumAllowedChannels(int numChannels) {
+        sendMessage(obtainMessage(CMD_SET_NUM_ALLOWED_CHANNELS, numChannels, 0));
+    }
+
+    /**
+     * Get number of allowed channels
+     *
+     * @return channel count, -1 on failure
+     *
+     * TODO: this is not a public API and needs to be removed in favor
+     * of asynchronous reporting. unused for now.
+     */
+    public int getNumAllowedChannels() {
+        return -1;
+    }
+
+    /**
+     * Set bluetooth coex mode:
+     *
+     * @param mode
+     *  BLUETOOTH_COEXISTENCE_MODE_ENABLED
+     *  BLUETOOTH_COEXISTENCE_MODE_DISABLED
+     *  BLUETOOTH_COEXISTENCE_MODE_SENSE
+     */
+    public void setBluetoothCoexistenceMode(int mode) {
+        sendMessage(obtainMessage(CMD_SET_BLUETOOTH_COEXISTENCE, mode, 0));
+    }
+
+    /**
+     * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
+     * some of the low-level scan parameters used by the driver are changed to
+     * reduce interference with A2DP streaming.
+     *
+     * @param isBluetoothPlaying whether to enable or disable this mode
+     */
+    public void setBluetoothScanMode(boolean isBluetoothPlaying) {
+        sendMessage(obtainMessage(CMD_SET_BLUETOOTH_SCAN_MODE, isBluetoothPlaying ? 1 : 0, 0));
+    }
+
+    /**
+     * Save configuration on supplicant
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     *
+     * TODO: deprecate this
+     */
+    public boolean saveConfig() {
+        return sendSyncMessage(CMD_SAVE_CONFIG).boolValue;
+    }
+
+    /**
+     * TODO: doc
+     */
+    public void requestCmWakeLock() {
+        sendMessage(CMD_REQUEST_CM_WAKELOCK);
+    }
+
+    /*********************************************************
+     * Internal private functions
+     ********************************************************/
+
+    class SyncReturn {
+        boolean boolValue;
+        int intValue;
+        String stringValue;
+        Object objValue;
+        List<WifiConfiguration> configList;
+    }
+
+    class SyncParams {
+        Object mParameter;
+        SyncReturn mSyncReturn;
+        SyncParams() {
+            mSyncReturn = new SyncReturn();
+        }
+        SyncParams(Object p) {
+            mParameter = p;
+            mSyncReturn = new SyncReturn();
+        }
+    }
+
+    /**
+     * message.arg2 is reserved to indicate synchronized
+     * message.obj is used to store SyncParams
+     */
+    private SyncReturn syncedSend(Message msg) {
+        SyncParams syncParams = (SyncParams) msg.obj;
+        msg.arg2 = SYNCHRONOUS_CALL;
+        synchronized(syncParams) {
+            if (DBG) Log.d(TAG, "syncedSend " + msg);
+            sendMessage(msg);
+            try {
+                syncParams.wait();
+            } catch (InterruptedException e) {
+                Log.e(TAG, "sendSyncMessage: unexpected interruption of wait()");
+                return null;
+            }
+        }
+        return syncParams.mSyncReturn;
+    }
+
+    private SyncReturn sendSyncMessage(Message msg) {
+        SyncParams syncParams = new SyncParams();
+        msg.obj = syncParams;
+        return syncedSend(msg);
+    }
+
+    private SyncReturn sendSyncMessage(int what, Object param) {
+        SyncParams syncParams = new SyncParams(param);
+        Message msg = obtainMessage(what, syncParams);
+        return syncedSend(msg);
+    }
+
+
+    private SyncReturn sendSyncMessage(int what) {
+        return sendSyncMessage(obtainMessage(what));
+    }
+
+    private void notifyOnMsgObject(Message msg) {
+        SyncParams syncParams = (SyncParams) msg.obj;
+        if (syncParams != null) {
+            synchronized(syncParams) {
+                if (DBG) Log.d(TAG, "notifyOnMsgObject " + msg);
+                syncParams.notify();
+            }
+        }
+        else {
+            Log.e(TAG, "Error! syncParams in notifyOnMsgObject is null");
+        }
+    }
+
+    private void setWifiState(int wifiState) {
+        final int previousWifiState = mWifiState.get();
+
+        try {
+            if (wifiState == WIFI_STATE_ENABLED) {
+                mBatteryStats.noteWifiOn(mLastEnableUid.get());
+            } else if (wifiState == WIFI_STATE_DISABLED) {
+                mBatteryStats.noteWifiOff(mLastEnableUid.get());
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to note battery stats in wifi");
+        }
+
+        mWifiState.set(wifiState);
+
+        if (DBG) Log.d(TAG, "setWifiState: " + getWifiStateByName());
+
+        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
+        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
+        mContext.sendStickyBroadcast(intent);
+    }
+
+    private void setWifiApState(int wifiApState) {
+        final int previousWifiApState = mWifiApState.get();
+
+        try {
+            if (wifiApState == WIFI_AP_STATE_ENABLED) {
+                mBatteryStats.noteWifiOn(mLastApEnableUid.get());
+            } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
+                mBatteryStats.noteWifiOff(mLastApEnableUid.get());
+            }
+        } catch (RemoteException e) {
+            Log.d(TAG, "Failed to note battery stats in wifi");
+        }
+
+        // Update state
+        mWifiApState.set(wifiApState);
+
+        if (DBG) Log.d(TAG, "setWifiApState: " + getWifiApStateByName());
+
+        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
+        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
+        mContext.sendStickyBroadcast(intent);
+    }
+
+    /**
+     * Parse the scan result line passed to us by wpa_supplicant (helper).
+     * @param line the line to parse
+     * @return the {@link ScanResult} object
+     */
+    private ScanResult parseScanResult(String line) {
+        ScanResult scanResult = null;
+        if (line != null) {
+            /*
+             * Cache implementation (LinkedHashMap) is not synchronized, thus,
+             * must synchronized here!
+             */
+            synchronized (mScanResultCache) {
+                String[] result = scanResultPattern.split(line);
+                if (3 <= result.length && result.length <= 5) {
+                    String bssid = result[0];
+                    // bssid | frequency | level | flags | ssid
+                    int frequency;
+                    int level;
+                    try {
+                        frequency = Integer.parseInt(result[1]);
+                        level = Integer.parseInt(result[2]);
+                        /* some implementations avoid negative values by adding 256
+                         * so we need to adjust for that here.
+                         */
+                        if (level > 0) level -= 256;
+                    } catch (NumberFormatException e) {
+                        frequency = 0;
+                        level = 0;
+                    }
+
+                    /*
+                     * The formatting of the results returned by
+                     * wpa_supplicant is intended to make the fields
+                     * line up nicely when printed,
+                     * not to make them easy to parse. So we have to
+                     * apply some heuristics to figure out which field
+                     * is the SSID and which field is the flags.
+                     */
+                    String ssid;
+                    String flags;
+                    if (result.length == 4) {
+                        if (result[3].charAt(0) == '[') {
+                            flags = result[3];
+                            ssid = "";
+                        } else {
+                            flags = "";
+                            ssid = result[3];
+                        }
+                    } else if (result.length == 5) {
+                        flags = result[3];
+                        ssid = result[4];
+                    } else {
+                        // Here, we must have 3 fields: no flags and ssid
+                        // set
+                        flags = "";
+                        ssid = "";
+                    }
+
+                    // bssid + ssid is the hash key
+                    String key = bssid + ssid;
+                    scanResult = mScanResultCache.get(key);
+                    if (scanResult != null) {
+                        scanResult.level = level;
+                        scanResult.SSID = ssid;
+                        scanResult.capabilities = flags;
+                        scanResult.frequency = frequency;
+                    } else {
+                        // Do not add scan results that have no SSID set
+                        if (0 < ssid.trim().length()) {
+                            scanResult =
+                                new ScanResult(
+                                    ssid, bssid, flags, level, frequency);
+                            mScanResultCache.put(key, scanResult);
+                        }
+                    }
+                } else {
+                    Log.w(TAG, "Misformatted scan result text with " +
+                          result.length + " fields: " + line);
+                }
+            }
+        }
+
+        return scanResult;
+    }
+
+    /**
+     * scanResults input format
+     * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
+     * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
+     */
+    private void setScanResults(String scanResults) {
+        if (scanResults == null) {
+            return;
+        }
+
+        List<ScanResult> scanList = new ArrayList<ScanResult>();
+
+        int lineCount = 0;
+
+        int scanResultsLen = scanResults.length();
+        // Parse the result string, keeping in mind that the last line does
+        // not end with a newline.
+        for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
+            if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
+                ++lineCount;
+
+                if (lineCount == 1) {
+                    lineBeg = lineEnd + 1;
+                    continue;
+                }
+                if (lineEnd > lineBeg) {
+                    String line = scanResults.substring(lineBeg, lineEnd);
+                    ScanResult scanResult = parseScanResult(line);
+                    if (scanResult != null) {
+                        scanList.add(scanResult);
+                    } else {
+                        Log.w(TAG, "misformatted scan result for: " + line);
+                    }
+                }
+                lineBeg = lineEnd + 1;
+            }
+        }
+
+        mScanResults = scanList;
+    }
+
+    private void configureNetworkProperties() {
+        try {
+            mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName));
+        } catch (SocketException e) {
+            Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName +
+                    ". e=" + e);
+            return;
+        } catch (NullPointerException e) {
+            Log.e(TAG, "NPE creating NetworkInterface. e=" + e);
+            return;
+        }
+        // TODO - fix this for v6
+        try {
+            mNetworkProperties.addAddress(InetAddress.getByAddress(
+                    NetworkUtils.v4IntToArray(mDhcpInfo.ipAddress)));
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Exception setting IpAddress using " + mDhcpInfo + ", e=" + e);
+        }
+
+        try {
+            mNetworkProperties.setGateway(InetAddress.getByAddress(NetworkUtils.v4IntToArray(
+                    mDhcpInfo.gateway)));
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Exception setting Gateway using " + mDhcpInfo + ", e=" + e);
+        }
+
+        try {
+            mNetworkProperties.addDns(InetAddress.getByAddress(
+                    NetworkUtils.v4IntToArray(mDhcpInfo.dns1)));
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Exception setting Dns1 using " + mDhcpInfo + ", e=" + e);
+        }
+        try {
+            mNetworkProperties.addDns(InetAddress.getByAddress(
+                    NetworkUtils.v4IntToArray(mDhcpInfo.dns2)));
+
+        } catch (UnknownHostException e) {
+            Log.e(TAG, "Exception setting Dns2 using " + mDhcpInfo + ", e=" + e);
+        }
+        // TODO - add proxy info
+    }
+
+
+    private void checkUseStaticIp() {
+        mUseStaticIp = false;
+        final ContentResolver cr = mContext.getContentResolver();
+        try {
+            if (Settings.System.getInt(cr, Settings.System.WIFI_USE_STATIC_IP) == 0) {
+                return;
+            }
+        } catch (Settings.SettingNotFoundException e) {
+            return;
+        }
+
+        try {
+            String addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_IP);
+            if (addr != null) {
+                mDhcpInfo.ipAddress = stringToIpAddr(addr);
+            } else {
+                return;
+            }
+            addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_GATEWAY);
+            if (addr != null) {
+                mDhcpInfo.gateway = stringToIpAddr(addr);
+            } else {
+                return;
+            }
+            addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_NETMASK);
+            if (addr != null) {
+                mDhcpInfo.netmask = stringToIpAddr(addr);
+            } else {
+                return;
+            }
+            addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS1);
+            if (addr != null) {
+                mDhcpInfo.dns1 = stringToIpAddr(addr);
+            } else {
+                return;
+            }
+            addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS2);
+            if (addr != null) {
+                mDhcpInfo.dns2 = stringToIpAddr(addr);
+            } else {
+                mDhcpInfo.dns2 = 0;
+            }
+        } catch (UnknownHostException e) {
+            return;
+        }
+        mUseStaticIp = true;
+    }
+
+    private static int stringToIpAddr(String addrString) throws UnknownHostException {
+        try {
+            String[] parts = addrString.split("\\.");
+            if (parts.length != 4) {
+                throw new UnknownHostException(addrString);
+            }
+
+            int a = Integer.parseInt(parts[0])      ;
+            int b = Integer.parseInt(parts[1]) <<  8;
+            int c = Integer.parseInt(parts[2]) << 16;
+            int d = Integer.parseInt(parts[3]) << 24;
+
+            return a | b | c | d;
+        } catch (NumberFormatException ex) {
+            throw new UnknownHostException(addrString);
+        }
+    }
+
+    private int getMaxDhcpRetries() {
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                                      Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
+                                      DEFAULT_MAX_DHCP_RETRIES);
+    }
+
+    private class SettingsObserver extends ContentObserver {
+        public SettingsObserver(Handler handler) {
+            super(handler);
+            ContentResolver cr = mContext.getContentResolver();
+            cr.registerContentObserver(Settings.System.getUriFor(
+                Settings.System.WIFI_USE_STATIC_IP), false, this);
+            cr.registerContentObserver(Settings.System.getUriFor(
+                Settings.System.WIFI_STATIC_IP), false, this);
+            cr.registerContentObserver(Settings.System.getUriFor(
+                Settings.System.WIFI_STATIC_GATEWAY), false, this);
+            cr.registerContentObserver(Settings.System.getUriFor(
+                Settings.System.WIFI_STATIC_NETMASK), false, this);
+            cr.registerContentObserver(Settings.System.getUriFor(
+                Settings.System.WIFI_STATIC_DNS1), false, this);
+            cr.registerContentObserver(Settings.System.getUriFor(
+                Settings.System.WIFI_STATIC_DNS2), false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+
+            boolean wasStaticIp = mUseStaticIp;
+            int oIp, oGw, oMsk, oDns1, oDns2;
+            oIp = oGw = oMsk = oDns1 = oDns2 = 0;
+            if (wasStaticIp) {
+                oIp = mDhcpInfo.ipAddress;
+                oGw = mDhcpInfo.gateway;
+                oMsk = mDhcpInfo.netmask;
+                oDns1 = mDhcpInfo.dns1;
+                oDns2 = mDhcpInfo.dns2;
+            }
+            checkUseStaticIp();
+
+            if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) {
+                return;
+            }
+
+            boolean changed =
+                (wasStaticIp != mUseStaticIp) ||
+                    (wasStaticIp && (
+                        oIp   != mDhcpInfo.ipAddress ||
+                        oGw   != mDhcpInfo.gateway ||
+                        oMsk  != mDhcpInfo.netmask ||
+                        oDns1 != mDhcpInfo.dns1 ||
+                        oDns2 != mDhcpInfo.dns2));
+
+            if (changed) {
+                sendMessage(CMD_RECONFIGURE_IP);
+                mConfigChanged = true;
+            }
+        }
+    }
+
+    /**
+     * Whether to disable coexistence mode while obtaining IP address. This
+     * logic will return true only if the current bluetooth
+     * headset/handsfree state is disconnected. This means if it is in an
+     * error state, we will NOT disable coexistence mode to err on the side
+     * of safety.
+     *
+     * @return Whether to disable coexistence mode.
+     */
+    private boolean shouldDisableCoexistenceMode() {
+        int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset());
+        return state == BluetoothHeadset.STATE_DISCONNECTED;
+    }
+
+    private void checkIsBluetoothPlaying() {
+        boolean isBluetoothPlaying = false;
+        Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks();
+
+        for (BluetoothDevice device : connected) {
+            if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) {
+                isBluetoothPlaying = true;
+                break;
+            }
+        }
+        setBluetoothScanMode(isBluetoothPlaying);
+    }
+
+    private void sendScanResultsAvailableBroadcast() {
+        if (!ActivityManagerNative.isSystemReady()) return;
+
+        mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
+    }
+
+    private void sendRssiChangeBroadcast(final int newRssi) {
+        if (!ActivityManagerNative.isSystemReady()) return;
+
+        Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
+        intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
+        mContext.sendBroadcast(intent);
+    }
+
+    private void sendNetworkStateChangeBroadcast(String bssid) {
+        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
+        intent.putExtra(WifiManager.EXTRA_NETWORK_PROPERTIES, mNetworkProperties);
+        if (bssid != null)
+            intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
+        mContext.sendStickyBroadcast(intent);
+    }
+
+    private void sendConfigChangeBroadcast() {
+        Intent intent = new Intent(WifiManager.CONFIG_CHANGED_ACTION);
+        intent.putExtra(WifiManager.EXTRA_NETWORK_PROPERTIES, mNetworkProperties);
+        mContext.sendBroadcast(intent);
+    }
+
+    private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) {
+        Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state);
+        if (failedAuth) {
+            intent.putExtra(
+                WifiManager.EXTRA_SUPPLICANT_ERROR,
+                WifiManager.ERROR_AUTHENTICATING);
+        }
+        mContext.sendStickyBroadcast(intent);
+    }
+
+    private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
+        if (!ActivityManagerNative.isSystemReady()) return;
+
+        Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
+        intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
+        mContext.sendBroadcast(intent);
+    }
+
+    /**
+     * Record the detailed state of a network.
+     * @param state the new @{code DetailedState}
+     */
+    private void setDetailedState(NetworkInfo.DetailedState state) {
+        Log.d(TAG, "setDetailed state, old ="
+                + mNetworkInfo.getDetailedState() + " and new state=" + state);
+        if (state != mNetworkInfo.getDetailedState()) {
+            mNetworkInfo.setDetailedState(state, null, null);
+        }
+    }
+
+    private static String removeDoubleQuotes(String string) {
+      if (string.length() <= 2) return "";
+      return string.substring(1, string.length() - 1);
+    }
+
+    private static String convertToQuotedString(String string) {
+        return "\"" + string + "\"";
+    }
+
+    private static String makeString(BitSet set, String[] strings) {
+        StringBuffer buf = new StringBuffer();
+        int nextSetBit = -1;
+
+        /* Make sure all set bits are in [0, strings.length) to avoid
+         * going out of bounds on strings.  (Shouldn't happen, but...) */
+        set = set.get(0, strings.length);
+
+        while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
+            buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
+        }
+
+        // remove trailing space
+        if (set.cardinality() > 0) {
+            buf.setLength(buf.length() - 1);
+        }
+
+        return buf.toString();
+    }
+
+    private static int lookupString(String string, String[] strings) {
+        int size = strings.length;
+
+        string = string.replace('-', '_');
+
+        for (int i = 0; i < size; i++)
+            if (string.equals(strings[i]))
+                return i;
+
+        // if we ever get here, we should probably add the
+        // value to WifiConfiguration to reflect that it's
+        // supported by the WPA supplicant
+        Log.w(TAG, "Failed to look-up a string: " + string);
+
+        return -1;
+    }
+
+    private int addOrUpdateNetworkNative(WifiConfiguration config) {
+        /*
+         * If the supplied networkId is -1, we create a new empty
+         * network configuration. Otherwise, the networkId should
+         * refer to an existing configuration.
+         */
+        int netId = config.networkId;
+        boolean newNetwork = netId == -1;
+        // networkId of -1 means we want to create a new network
+
+        if (newNetwork) {
+            netId = WifiNative.addNetworkCommand();
+            if (netId < 0) {
+                Log.e(TAG, "Failed to add a network!");
+                return -1;
+          }
+        }
+
+        setVariables: {
+
+            if (config.SSID != null &&
+                    !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.ssidVarName,
+                        config.SSID)) {
+                Log.d(TAG, "failed to set SSID: "+config.SSID);
+                break setVariables;
+            }
+
+            if (config.BSSID != null &&
+                    !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.bssidVarName,
+                        config.BSSID)) {
+                Log.d(TAG, "failed to set BSSID: "+config.BSSID);
+                break setVariables;
+            }
+
+            String allowedKeyManagementString =
+                makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
+            if (config.allowedKeyManagement.cardinality() != 0 &&
+                    !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.KeyMgmt.varName,
+                        allowedKeyManagementString)) {
+                Log.d(TAG, "failed to set key_mgmt: "+
+                        allowedKeyManagementString);
+                break setVariables;
+            }
+
+            String allowedProtocolsString =
+                makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
+            if (config.allowedProtocols.cardinality() != 0 &&
+                    !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.Protocol.varName,
+                        allowedProtocolsString)) {
+                Log.d(TAG, "failed to set proto: "+
+                        allowedProtocolsString);
+                break setVariables;
+            }
+
+            String allowedAuthAlgorithmsString =
+                makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
+            if (config.allowedAuthAlgorithms.cardinality() != 0 &&
+                    !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.AuthAlgorithm.varName,
+                        allowedAuthAlgorithmsString)) {
+                Log.d(TAG, "failed to set auth_alg: "+
+                        allowedAuthAlgorithmsString);
+                break setVariables;
+            }
+
+            String allowedPairwiseCiphersString =
+                    makeString(config.allowedPairwiseCiphers,
+                    WifiConfiguration.PairwiseCipher.strings);
+            if (config.allowedPairwiseCiphers.cardinality() != 0 &&
+                    !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.PairwiseCipher.varName,
+                        allowedPairwiseCiphersString)) {
+                Log.d(TAG, "failed to set pairwise: "+
+                        allowedPairwiseCiphersString);
+                break setVariables;
+            }
+
+            String allowedGroupCiphersString =
+                makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
+            if (config.allowedGroupCiphers.cardinality() != 0 &&
+                    !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.GroupCipher.varName,
+                        allowedGroupCiphersString)) {
+                Log.d(TAG, "failed to set group: "+
+                        allowedGroupCiphersString);
+                break setVariables;
+            }
+
+            // Prevent client screw-up by passing in a WifiConfiguration we gave it
+            // by preventing "*" as a key.
+            if (config.preSharedKey != null && !config.preSharedKey.equals("*") &&
+                    !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.pskVarName,
+                        config.preSharedKey)) {
+                Log.d(TAG, "failed to set psk: "+config.preSharedKey);
+                break setVariables;
+            }
+
+            boolean hasSetKey = false;
+            if (config.wepKeys != null) {
+                for (int i = 0; i < config.wepKeys.length; i++) {
+                    // Prevent client screw-up by passing in a WifiConfiguration we gave it
+                    // by preventing "*" as a key.
+                    if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) {
+                        if (!WifiNative.setNetworkVariableCommand(
+                                    netId,
+                                    WifiConfiguration.wepKeyVarNames[i],
+                                    config.wepKeys[i])) {
+                            Log.d(TAG,
+                                    "failed to set wep_key"+i+": " +
+                                    config.wepKeys[i]);
+                            break setVariables;
+                        }
+                        hasSetKey = true;
+                    }
+                }
+            }
+
+            if (hasSetKey) {
+                if (!WifiNative.setNetworkVariableCommand(
+                            netId,
+                            WifiConfiguration.wepTxKeyIdxVarName,
+                            Integer.toString(config.wepTxKeyIndex))) {
+                    Log.d(TAG,
+                            "failed to set wep_tx_keyidx: "+
+                            config.wepTxKeyIndex);
+                    break setVariables;
+                }
+            }
+
+            if (!WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.priorityVarName,
+                        Integer.toString(config.priority))) {
+                Log.d(TAG, config.SSID + ": failed to set priority: "
+                        +config.priority);
+                break setVariables;
+            }
+
+            if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand(
+                        netId,
+                        WifiConfiguration.hiddenSSIDVarName,
+                        Integer.toString(config.hiddenSSID ? 1 : 0))) {
+                Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
+                        config.hiddenSSID);
+                break setVariables;
+            }
+
+            for (WifiConfiguration.EnterpriseField field
+                    : config.enterpriseFields) {
+                String varName = field.varName();
+                String value = field.value();
+                if (value != null) {
+                    if (field != config.eap) {
+                        value = (value.length() == 0) ? "NULL" : convertToQuotedString(value);
+                    }
+                    if (!WifiNative.setNetworkVariableCommand(
+                                netId,
+                                varName,
+                                value)) {
+                        Log.d(TAG, config.SSID + ": failed to set " + varName +
+                                ": " + value);
+                        break setVariables;
+                    }
+                }
+            }
+            return netId;
+        }
+
+        if (newNetwork) {
+            WifiNative.removeNetworkCommand(netId);
+            Log.d(TAG,
+                    "Failed to set a network variable, removed network: "
+                    + netId);
+        }
+
+        return -1;
+    }
+
+    private List<WifiConfiguration> getConfiguredNetworksNative() {
+        String listStr = WifiNative.listNetworksCommand();
+
+        List<WifiConfiguration> networks =
+            new ArrayList<WifiConfiguration>();
+        if (listStr == null)
+            return networks;
+
+        String[] lines = listStr.split("\n");
+        // Skip the first line, which is a header
+        for (int i = 1; i < lines.length; i++) {
+            String[] result = lines[i].split("\t");
+            // network-id | ssid | bssid | flags
+            WifiConfiguration config = new WifiConfiguration();
+            try {
+                config.networkId = Integer.parseInt(result[0]);
+            } catch(NumberFormatException e) {
+                continue;
+            }
+            if (result.length > 3) {
+                if (result[3].indexOf("[CURRENT]") != -1)
+                    config.status = WifiConfiguration.Status.CURRENT;
+                else if (result[3].indexOf("[DISABLED]") != -1)
+                    config.status = WifiConfiguration.Status.DISABLED;
+                else
+                    config.status = WifiConfiguration.Status.ENABLED;
+            } else {
+                config.status = WifiConfiguration.Status.ENABLED;
+            }
+            readNetworkVariables(config);
+            networks.add(config);
+        }
+        return networks;
+    }
+
+    /**
+     * Read the variables from the supplicant daemon that are needed to
+     * fill in the WifiConfiguration object.
+     *
+     * @param config the {@link WifiConfiguration} object to be filled in.
+     */
+    private void readNetworkVariables(WifiConfiguration config) {
+
+        int netId = config.networkId;
+        if (netId < 0)
+            return;
+
+        /*
+         * TODO: maybe should have a native method that takes an array of
+         * variable names and returns an array of values. But we'd still
+         * be doing a round trip to the supplicant daemon for each variable.
+         */
+        String value;
+
+        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
+        if (!TextUtils.isEmpty(value)) {
+            config.SSID = removeDoubleQuotes(value);
+        } else {
+            config.SSID = null;
+        }
+
+        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName);
+        if (!TextUtils.isEmpty(value)) {
+            config.BSSID = value;
+        } else {
+            config.BSSID = null;
+        }
+
+        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
+        config.priority = -1;
+        if (!TextUtils.isEmpty(value)) {
+            try {
+                config.priority = Integer.parseInt(value);
+            } catch (NumberFormatException ignore) {
+            }
+        }
+
+        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName);
+        config.hiddenSSID = false;
+        if (!TextUtils.isEmpty(value)) {
+            try {
+                config.hiddenSSID = Integer.parseInt(value) != 0;
+            } catch (NumberFormatException ignore) {
+            }
+        }
+
+        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName);
+        config.wepTxKeyIndex = -1;
+        if (!TextUtils.isEmpty(value)) {
+            try {
+                config.wepTxKeyIndex = Integer.parseInt(value);
+            } catch (NumberFormatException ignore) {
+            }
+        }
+
+        for (int i = 0; i < 4; i++) {
+            value = WifiNative.getNetworkVariableCommand(netId,
+                    WifiConfiguration.wepKeyVarNames[i]);
+            if (!TextUtils.isEmpty(value)) {
+                config.wepKeys[i] = value;
+            } else {
+                config.wepKeys[i] = null;
+            }
+        }
+
+        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName);
+        if (!TextUtils.isEmpty(value)) {
+            config.preSharedKey = value;
+        } else {
+            config.preSharedKey = null;
+        }
+
+        value = WifiNative.getNetworkVariableCommand(config.networkId,
+                WifiConfiguration.Protocol.varName);
+        if (!TextUtils.isEmpty(value)) {
+            String vals[] = value.split(" ");
+            for (String val : vals) {
+                int index =
+                    lookupString(val, WifiConfiguration.Protocol.strings);
+                if (0 <= index) {
+                    config.allowedProtocols.set(index);
+                }
+            }
+        }
+
+        value = WifiNative.getNetworkVariableCommand(config.networkId,
+                WifiConfiguration.KeyMgmt.varName);
+        if (!TextUtils.isEmpty(value)) {
+            String vals[] = value.split(" ");
+            for (String val : vals) {
+                int index =
+                    lookupString(val, WifiConfiguration.KeyMgmt.strings);
+                if (0 <= index) {
+                    config.allowedKeyManagement.set(index);
+                }
+            }
+        }
+
+        value = WifiNative.getNetworkVariableCommand(config.networkId,
+                WifiConfiguration.AuthAlgorithm.varName);
+        if (!TextUtils.isEmpty(value)) {
+            String vals[] = value.split(" ");
+            for (String val : vals) {
+                int index =
+                    lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
+                if (0 <= index) {
+                    config.allowedAuthAlgorithms.set(index);
+                }
+            }
+        }
+
+        value = WifiNative.getNetworkVariableCommand(config.networkId,
+                WifiConfiguration.PairwiseCipher.varName);
+        if (!TextUtils.isEmpty(value)) {
+            String vals[] = value.split(" ");
+            for (String val : vals) {
+                int index =
+                    lookupString(val, WifiConfiguration.PairwiseCipher.strings);
+                if (0 <= index) {
+                    config.allowedPairwiseCiphers.set(index);
+                }
+            }
+        }
+
+        value = WifiNative.getNetworkVariableCommand(config.networkId,
+                WifiConfiguration.GroupCipher.varName);
+        if (!TextUtils.isEmpty(value)) {
+            String vals[] = value.split(" ");
+            for (String val : vals) {
+                int index =
+                    lookupString(val, WifiConfiguration.GroupCipher.strings);
+                if (0 <= index) {
+                    config.allowedGroupCiphers.set(index);
+                }
+            }
+        }
+
+        for (WifiConfiguration.EnterpriseField field :
+                config.enterpriseFields) {
+            value = WifiNative.getNetworkVariableCommand(netId,
+                    field.varName());
+            if (!TextUtils.isEmpty(value)) {
+                if (field != config.eap) value = removeDoubleQuotes(value);
+                field.setValue(value);
+            }
+        }
+
+    }
+
+    /**
+     * Poll for info not reported via events
+     * RSSI & Linkspeed
+     */
+    private void requestPolledInfo() {
+        int newRssi = WifiNative.getRssiCommand();
+        if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
+            /* some implementations avoid negative values by adding 256
+             * so we need to adjust for that here.
+             */
+            if (newRssi > 0) newRssi -= 256;
+            mWifiInfo.setRssi(newRssi);
+            /*
+             * Rather then sending the raw RSSI out every time it
+             * changes, we precalculate the signal level that would
+             * be displayed in the status bar, and only send the
+             * broadcast if that much more coarse-grained number
+             * changes. This cuts down greatly on the number of
+             * broadcasts, at the cost of not mWifiInforming others
+             * interested in RSSI of all the changes in signal
+             * level.
+             */
+            // TODO: The second arg to the call below needs to be a symbol somewhere, but
+            // it's actually the size of an array of icons that's private
+            // to StatusBar Policy.
+            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
+            if (newSignalLevel != mLastSignalLevel) {
+                sendRssiChangeBroadcast(newRssi);
+            }
+            mLastSignalLevel = newSignalLevel;
+        } else {
+            mWifiInfo.setRssi(-200);
+        }
+        int newLinkSpeed = WifiNative.getLinkSpeedCommand();
+        if (newLinkSpeed != -1) {
+            mWifiInfo.setLinkSpeed(newLinkSpeed);
+        }
+    }
+
+    /**
+     * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
+     * using the interface, stopping DHCP & disabling interface
+     */
+    private void handleNetworkDisconnect() {
+        Log.d(TAG, "Reset connections and stopping DHCP");
+
+        /*
+         * Reset connections & stop DHCP
+         */
+        NetworkUtils.resetConnections(mInterfaceName);
+
+        if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+            Log.e(TAG, "Could not stop DHCP");
+        }
+
+        /* Disable interface */
+        NetworkUtils.disableInterface(mInterfaceName);
+
+        /* send event to CM & network change broadcast */
+        setDetailedState(DetailedState.DISCONNECTED);
+        sendNetworkStateChangeBroadcast(mLastBssid);
+
+        /* Reset data structures */
+        mWifiInfo.setIpAddress(0);
+        mWifiInfo.setBSSID(null);
+        mWifiInfo.setSSID(null);
+        mWifiInfo.setNetworkId(-1);
+
+        /* Clear network properties */
+        mNetworkProperties.clear();
+
+        mLastBssid= null;
+        mLastNetworkId = -1;
+
+    }
+
+
+    /*********************************************************
+     * Notifications from WifiMonitor
+     ********************************************************/
+
+    /**
+     * A structure for supplying information about a supplicant state
+     * change in the STATE_CHANGE event message that comes from the
+     * WifiMonitor
+     * thread.
+     */
+    private static class StateChangeResult {
+        StateChangeResult(int networkId, String BSSID, Object state) {
+            this.state = state;
+            this.BSSID = BSSID;
+            this.networkId = networkId;
+        }
+        int networkId;
+        String BSSID;
+        Object state;
+    }
+
+    /**
+     * Send the tracker a notification that a user-entered password key
+     * may be incorrect (i.e., caused authentication to fail).
+     */
+    void notifyPasswordKeyMayBeIncorrect() {
+        sendMessage(PASSWORD_MAY_BE_INCORRECT_EVENT);
+    }
+
+    /**
+     * Send the tracker a notification that a connection to the supplicant
+     * daemon has been established.
+     */
+    void notifySupplicantConnection() {
+        sendMessage(SUP_CONNECTION_EVENT);
+    }
+
+    /**
+     * Send the tracker a notification that a connection to the supplicant
+     * daemon has been established.
+     */
+    void notifySupplicantLost() {
+        sendMessage(SUP_DISCONNECTION_EVENT);
+    }
+
+    /**
+     * Send the tracker a notification that the state of Wifi connectivity
+     * has changed.
+     * @param networkId the configured network on which the state change occurred
+     * @param newState the new network state
+     * @param BSSID when the new state is {@link DetailedState#CONNECTED
+     * NetworkInfo.DetailedState.CONNECTED},
+     * this is the MAC address of the access point. Otherwise, it
+     * is {@code null}.
+     */
+    void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) {
+        if (newState == NetworkInfo.DetailedState.CONNECTED) {
+            sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT,
+                    new StateChangeResult(networkId, BSSID, newState)));
+        } else {
+            sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT,
+                    new StateChangeResult(networkId, BSSID, newState)));
+        }
+    }
+
+    /**
+     * Send the tracker a notification that the state of the supplicant
+     * has changed.
+     * @param networkId the configured network on which the state change occurred
+     * @param newState the new {@code SupplicantState}
+     */
+    void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
+        sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
+                new StateChangeResult(networkId, BSSID, newState)));
+    }
+
+    /**
+     * Send the tracker a notification that a scan has completed, and results
+     * are available.
+     */
+    void notifyScanResultsAvailable() {
+        /**
+         * Switch scan mode over to passive.
+         * Turning off scan-only mode happens only in "Connect" mode
+         */
+        setScanType(false);
+        sendMessage(SCAN_RESULTS_EVENT);
+    }
+
+    void notifyDriverStarted() {
+        sendMessage(DRIVER_START_EVENT);
+    }
+
+    void notifyDriverStopped() {
+        sendMessage(DRIVER_STOP_EVENT);
+    }
+
+    void notifyDriverHung() {
+        setWifiEnabled(false);
+        setWifiEnabled(true);
+    }
+
+
+    /********************************************************
+     * HSM states
+     *******************************************************/
+
+    class DefaultState extends HierarchicalState {
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            SyncParams syncParams;
+            switch (message.what) {
+                    /* Synchronous call returns */
+                case CMD_PING_SUPPLICANT:
+                case CMD_START_SCAN:
+                case CMD_DISCONNECT:
+                case CMD_RECONNECT:
+                case CMD_REASSOCIATE:
+                case CMD_REMOVE_NETWORK:
+                case CMD_ENABLE_NETWORK:
+                case CMD_DISABLE_NETWORK:
+                case CMD_ADD_OR_UPDATE_NETWORK:
+                case CMD_GET_RSSI:
+                case CMD_GET_RSSI_APPROX:
+                case CMD_GET_LINK_SPEED:
+                case CMD_GET_MAC_ADDR:
+                case CMD_SAVE_CONFIG:
+                case CMD_CONNECTION_STATUS:
+                case CMD_GET_NETWORK_CONFIG:
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = false;
+                        syncParams.mSyncReturn.intValue = -1;
+                        syncParams.mSyncReturn.stringValue = null;
+                        syncParams.mSyncReturn.configList = null;
+                        notifyOnMsgObject(message);
+                    }
+                    break;
+                case CMD_ENABLE_RSSI_POLL:
+                    mEnableRssiPolling = (message.arg1 == 1);
+                    mSupplicantStateTracker.sendMessage(CMD_ENABLE_RSSI_POLL);
+                    break;
+                    /* Discard */
+                case CMD_LOAD_DRIVER:
+                case CMD_UNLOAD_DRIVER:
+                case CMD_START_SUPPLICANT:
+                case CMD_STOP_SUPPLICANT:
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case CMD_START_AP:
+                case CMD_STOP_AP:
+                case CMD_RECONFIGURE_IP:
+                case SUP_CONNECTION_EVENT:
+                case SUP_DISCONNECTION_EVENT:
+                case DRIVER_START_EVENT:
+                case DRIVER_STOP_EVENT:
+                case DRIVER_HUNG_EVENT:
+                case NETWORK_CONNECTION_EVENT:
+                case NETWORK_DISCONNECTION_EVENT:
+                case SCAN_RESULTS_EVENT:
+                case SUPPLICANT_STATE_CHANGE_EVENT:
+                case PASSWORD_MAY_BE_INCORRECT_EVENT:
+                case CMD_BLACKLIST_NETWORK:
+                case CMD_CLEAR_BLACKLIST:
+                case CMD_SET_SCAN_MODE:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_POWER_MODE:
+                case CMD_SET_BLUETOOTH_COEXISTENCE:
+                case CMD_SET_BLUETOOTH_SCAN_MODE:
+                case CMD_SET_NUM_ALLOWED_CHANNELS:
+                case CMD_REQUEST_CM_WAKELOCK:
+                    break;
+                default:
+                    Log.e(TAG, "Error! unhandled message" + message);
+                    break;
+            }
+            return HANDLED;
+        }
+    }
+
+    class InitialState extends HierarchicalState {
+        @Override
+        //TODO: could move logging into a common class
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            // [31-8] Reserved for future use
+            // [7 - 0] HSM state change
+            // 50021 wifi_state_changed (custom|1|5)
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+            if (WifiNative.isDriverLoaded()) {
+                transitionTo(mDriverLoadedState);
+            }
+            else {
+                transitionTo(mDriverUnloadedState);
+            }
+        }
+    }
+
+    class DriverLoadingState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+            final Message message = new Message();
+            message.copyFrom(getCurrentMessage());
+            /* TODO: add a timeout to fail when driver load is hung.
+             * Similarly for driver unload.
+             */
+            new Thread(new Runnable() {
+                public void run() {
+                    sWakeLock.acquire();
+                    //enabling state
+                    switch(message.arg1) {
+                        case WIFI_STATE_ENABLING:
+                            setWifiState(WIFI_STATE_ENABLING);
+                            break;
+                        case WIFI_AP_STATE_ENABLING:
+                            setWifiApState(WIFI_AP_STATE_ENABLING);
+                            break;
+                    }
+
+                    if(WifiNative.loadDriver()) {
+                        Log.d(TAG, "Driver load successful");
+                        sendMessage(CMD_LOAD_DRIVER_SUCCESS);
+                    } else {
+                        Log.e(TAG, "Failed to load driver!");
+                        switch(message.arg1) {
+                            case WIFI_STATE_ENABLING:
+                                setWifiState(WIFI_STATE_UNKNOWN);
+                                break;
+                            case WIFI_AP_STATE_ENABLING:
+                                setWifiApState(WIFI_AP_STATE_FAILED);
+                                break;
+                        }
+                        sendMessage(CMD_LOAD_DRIVER_FAILURE);
+                    }
+                    sWakeLock.release();
+                }
+            }).start();
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_LOAD_DRIVER_SUCCESS:
+                    transitionTo(mDriverLoadedState);
+                    break;
+                case CMD_LOAD_DRIVER_FAILURE:
+                    transitionTo(mDriverFailedState);
+                    break;
+                case CMD_LOAD_DRIVER:
+                case CMD_UNLOAD_DRIVER:
+                case CMD_START_SUPPLICANT:
+                case CMD_STOP_SUPPLICANT:
+                case CMD_START_AP:
+                case CMD_STOP_AP:
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case CMD_SET_SCAN_MODE:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_POWER_MODE:
+                case CMD_SET_BLUETOOTH_COEXISTENCE:
+                case CMD_SET_BLUETOOTH_SCAN_MODE:
+                case CMD_SET_NUM_ALLOWED_CHANNELS:
+                case CMD_START_PACKET_FILTERING:
+                case CMD_STOP_PACKET_FILTERING:
+                    deferMessage(message);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DriverLoadedState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch(message.what) {
+                case CMD_UNLOAD_DRIVER:
+                    transitionTo(mDriverUnloadingState);
+                    break;
+                case CMD_START_SUPPLICANT:
+                    if(WifiNative.startSupplicant()) {
+                        Log.d(TAG, "Supplicant start successful");
+                        mWifiMonitor.startMonitoring();
+                        setWifiState(WIFI_STATE_ENABLED);
+                        transitionTo(mWaitForSupState);
+                    } else {
+                        Log.e(TAG, "Failed to start supplicant!");
+                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
+                    }
+                    break;
+                case CMD_START_AP:
+                    try {
+                        nwService.startAccessPoint((WifiConfiguration) message.obj,
+                                    mInterfaceName,
+                                    SOFTAP_IFACE);
+                    } catch(Exception e) {
+                        Log.e(TAG, "Exception in startAccessPoint()");
+                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
+                        break;
+                    }
+                    Log.d(TAG, "Soft AP start successful");
+                    setWifiApState(WIFI_AP_STATE_ENABLED);
+                    transitionTo(mSoftApStartedState);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DriverUnloadingState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+            final Message message = new Message();
+            message.copyFrom(getCurrentMessage());
+            new Thread(new Runnable() {
+                public void run() {
+                    if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+                    sWakeLock.acquire();
+                    if(WifiNative.unloadDriver()) {
+                        Log.d(TAG, "Driver unload successful");
+                        sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
+
+                        switch(message.arg1) {
+                            case WIFI_STATE_DISABLED:
+                            case WIFI_STATE_UNKNOWN:
+                                setWifiState(message.arg1);
+                                break;
+                            case WIFI_AP_STATE_DISABLED:
+                            case WIFI_AP_STATE_FAILED:
+                                setWifiApState(message.arg1);
+                                break;
+                        }
+                    } else {
+                        Log.e(TAG, "Failed to unload driver!");
+                        sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
+
+                        switch(message.arg1) {
+                            case WIFI_STATE_DISABLED:
+                            case WIFI_STATE_UNKNOWN:
+                                setWifiState(WIFI_STATE_UNKNOWN);
+                                break;
+                            case WIFI_AP_STATE_DISABLED:
+                            case WIFI_AP_STATE_FAILED:
+                                setWifiApState(WIFI_AP_STATE_FAILED);
+                                break;
+                        }
+                    }
+                    sWakeLock.release();
+                }
+            }).start();
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_UNLOAD_DRIVER_SUCCESS:
+                    transitionTo(mDriverUnloadedState);
+                    break;
+                case CMD_UNLOAD_DRIVER_FAILURE:
+                    transitionTo(mDriverFailedState);
+                    break;
+                case CMD_LOAD_DRIVER:
+                case CMD_UNLOAD_DRIVER:
+                case CMD_START_SUPPLICANT:
+                case CMD_STOP_SUPPLICANT:
+                case CMD_START_AP:
+                case CMD_STOP_AP:
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case CMD_SET_SCAN_MODE:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_POWER_MODE:
+                case CMD_SET_BLUETOOTH_COEXISTENCE:
+                case CMD_SET_BLUETOOTH_SCAN_MODE:
+                case CMD_SET_NUM_ALLOWED_CHANNELS:
+                case CMD_START_PACKET_FILTERING:
+                case CMD_STOP_PACKET_FILTERING:
+                    deferMessage(message);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DriverUnloadedState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_LOAD_DRIVER:
+                    transitionTo(mDriverLoadingState);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DriverFailedState extends HierarchicalState {
+        @Override
+        public void enter() {
+            Log.e(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            return NOT_HANDLED;
+        }
+    }
+
+
+    class WaitForSupState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch(message.what) {
+                case SUP_CONNECTION_EVENT:
+                    Log.d(TAG, "Supplicant connection established");
+                    mSupplicantStateTracker.resetSupplicantState();
+                    /* Initialize data structures */
+                    mLastBssid = null;
+                    mLastNetworkId = -1;
+                    mLastSignalLevel = -1;
+
+                    mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
+
+                    //TODO: initialize and fix multicast filtering
+                    //mWM.initializeMulticastFiltering();
+
+                    if (mBluetoothA2dp == null) {
+                        mBluetoothA2dp = new BluetoothA2dp(mContext);
+                    }
+                    checkIsBluetoothPlaying();
+
+                    checkUseStaticIp();
+                    sendSupplicantConnectionChangedBroadcast(true);
+                    transitionTo(mDriverSupReadyState);
+                    break;
+                case CMD_STOP_SUPPLICANT:
+                    Log.d(TAG, "Stop supplicant received");
+                    WifiNative.stopSupplicant();
+                    transitionTo(mDriverLoadedState);
+                    break;
+                    /* Fail soft ap when waiting for supplicant start */
+                case CMD_START_AP:
+                    Log.d(TAG, "Failed to start soft AP with a running supplicant");
+                    setWifiApState(WIFI_AP_STATE_FAILED);
+                    break;
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case CMD_SET_SCAN_MODE:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_POWER_MODE:
+                case CMD_SET_BLUETOOTH_COEXISTENCE:
+                case CMD_SET_BLUETOOTH_SCAN_MODE:
+                case CMD_SET_NUM_ALLOWED_CHANNELS:
+                case CMD_START_PACKET_FILTERING:
+                case CMD_STOP_PACKET_FILTERING:
+                    deferMessage(message);
+                    break;
+                case CMD_STOP_AP:
+                case CMD_START_SUPPLICANT:
+                case CMD_UNLOAD_DRIVER:
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DriverSupReadyState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+            /* Initialize for connect mode operation at start */
+            mIsScanMode = false;
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            SyncParams syncParams;
+            switch(message.what) {
+                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
+                    Log.d(TAG, "Stop supplicant received");
+                    WifiNative.stopSupplicant();
+                    //$FALL-THROUGH$
+                case SUP_DISCONNECTION_EVENT:  /* Supplicant died */
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    WifiNative.closeSupplicantConnection();
+                    handleNetworkDisconnect();
+                    sendSupplicantConnectionChangedBroadcast(false);
+                    mSupplicantStateTracker.resetSupplicantState();
+                    transitionTo(mDriverLoadedState);
+
+                    /* When supplicant dies, unload driver and enter failed state */
+                    //TODO: consider bringing up supplicant again
+                    if (message.what == SUP_DISCONNECTION_EVENT) {
+                        Log.d(TAG, "Supplicant died, unloading driver");
+                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
+                    }
+                    break;
+                case CMD_START_DRIVER:
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    WifiNative.startDriverCommand();
+                    transitionTo(mDriverStartingState);
+                    break;
+                case SCAN_RESULTS_EVENT:
+                    setScanResults(WifiNative.scanResultsCommand());
+                    sendScanResultsAvailableBroadcast();
+                    break;
+                case CMD_PING_SUPPLICANT:
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.boolValue = WifiNative.pingCommand();
+                    notifyOnMsgObject(message);
+                    break;
+                case CMD_ADD_OR_UPDATE_NETWORK:
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    syncParams = (SyncParams) message.obj;
+                    WifiConfiguration config = (WifiConfiguration) syncParams.mParameter;
+                    syncParams.mSyncReturn.intValue = addOrUpdateNetworkNative(config);
+                    notifyOnMsgObject(message);
+                    break;
+                case CMD_REMOVE_NETWORK:
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = WifiNative.removeNetworkCommand(
+                                message.arg1);
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.removeNetworkCommand(message.arg1);
+                    }
+                    break;
+                case CMD_ENABLE_NETWORK:
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter;
+                        syncParams.mSyncReturn.boolValue = WifiNative.enableNetworkCommand(
+                                enableNetParams.netId, enableNetParams.disableOthers);
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.enableNetworkCommand(message.arg1, message.arg2 == 1);
+                    }
+                    break;
+                case CMD_DISABLE_NETWORK:
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = WifiNative.disableNetworkCommand(
+                                message.arg1);
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.disableNetworkCommand(message.arg1);
+                    }
+                    break;
+                case CMD_BLACKLIST_NETWORK:
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    WifiNative.addToBlacklistCommand((String)message.obj);
+                    break;
+                case CMD_CLEAR_BLACKLIST:
+                    WifiNative.clearBlacklistCommand();
+                    break;
+                case CMD_GET_NETWORK_CONFIG:
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.configList = getConfiguredNetworksNative();
+                    notifyOnMsgObject(message);
+                    break;
+                case CMD_SAVE_CONFIG:
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = WifiNative.saveConfigCommand();
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.saveConfigCommand();
+                    }
+                    // Inform the backup manager about a data change
+                    IBackupManager ibm = IBackupManager.Stub.asInterface(
+                            ServiceManager.getService(Context.BACKUP_SERVICE));
+                    if (ibm != null) {
+                        try {
+                            ibm.dataChanged("com.android.providers.settings");
+                        } catch (Exception e) {
+                            // Try again later
+                        }
+                    }
+                    break;
+                case CMD_CONNECTION_STATUS:
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.stringValue = WifiNative.statusCommand();
+                    notifyOnMsgObject(message);
+                    break;
+                case CMD_GET_MAC_ADDR:
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.stringValue = WifiNative.getMacAddressCommand();
+                    notifyOnMsgObject(message);
+                    break;
+                    /* Cannot start soft AP while in client mode */
+                case CMD_START_AP:
+                    Log.d(TAG, "Failed to start soft AP with a running supplicant");
+                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+                    setWifiApState(WIFI_AP_STATE_FAILED);
+                    break;
+                case CMD_SET_SCAN_MODE:
+                    mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    class DriverStartingState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch(message.what) {
+                case DRIVER_START_EVENT:
+                    transitionTo(mDriverStartedState);
+                    break;
+                    /* Queue driver commands & connection events */
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case SUPPLICANT_STATE_CHANGE_EVENT:
+                case NETWORK_CONNECTION_EVENT:
+                case NETWORK_DISCONNECTION_EVENT:
+                case PASSWORD_MAY_BE_INCORRECT_EVENT:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_POWER_MODE:
+                case CMD_SET_BLUETOOTH_COEXISTENCE:
+                case CMD_SET_BLUETOOTH_SCAN_MODE:
+                case CMD_SET_NUM_ALLOWED_CHANNELS:
+                case CMD_START_PACKET_FILTERING:
+                case CMD_STOP_PACKET_FILTERING:
+                    deferMessage(message);
+                    break;
+                    /* Queue the asynchronous version of these commands */
+                case CMD_START_SCAN:
+                case CMD_DISCONNECT:
+                case CMD_REASSOCIATE:
+                case CMD_RECONNECT:
+                    if (message.arg2 != SYNCHRONOUS_CALL) {
+                        deferMessage(message);
+                    }
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DriverStartedState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+            try {
+                mBatteryStats.noteWifiRunning();
+            } catch (RemoteException ignore) {}
+
+            /* Initialize channel count */
+            setNumAllowedChannels();
+
+            if (mIsScanMode) {
+                WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
+                WifiNative.disconnectCommand();
+                transitionTo(mScanModeState);
+            } else {
+                WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
+                /* If supplicant has already connected, before we could finish establishing
+                 * the control channel connection, we miss all the supplicant events.
+                 * Disconnect and reconnect when driver has started to ensure we receive
+                 * all supplicant events.
+                 *
+                 * TODO: This is a bit unclean, ideally the supplicant should never
+                 * connect until told to do so by the framework
+                 */
+                WifiNative.disconnectCommand();
+                WifiNative.reconnectCommand();
+                transitionTo(mConnectModeState);
+            }
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            SyncParams syncParams;
+            switch(message.what) {
+                case CMD_SET_SCAN_TYPE:
+                    if (message.arg1 == SCAN_ACTIVE) {
+                        WifiNative.setScanModeCommand(true);
+                    } else {
+                        WifiNative.setScanModeCommand(false);
+                    }
+                    break;
+                case CMD_SET_POWER_MODE:
+                    WifiNative.setPowerModeCommand(message.arg1);
+                    break;
+                case CMD_SET_BLUETOOTH_COEXISTENCE:
+                    WifiNative.setBluetoothCoexistenceModeCommand(message.arg1);
+                    break;
+                case CMD_SET_BLUETOOTH_SCAN_MODE:
+                    WifiNative.setBluetoothCoexistenceScanModeCommand(message.arg1 == 1);
+                    break;
+                case CMD_SET_NUM_ALLOWED_CHANNELS:
+                    mNumAllowedChannels = message.arg1;
+                    WifiNative.setNumAllowedChannelsCommand(message.arg1);
+                    break;
+                case CMD_START_DRIVER:
+                    /* Ignore another driver start */
+                    break;
+                case CMD_STOP_DRIVER:
+                    WifiNative.stopDriverCommand();
+                    transitionTo(mDriverStoppingState);
+                    break;
+                case CMD_REQUEST_CM_WAKELOCK:
+                    if (mCm == null) {
+                        mCm = (ConnectivityManager)mContext.getSystemService(
+                                Context.CONNECTIVITY_SERVICE);
+                    }
+                    mCm.requestNetworkTransitionWakelock(TAG);
+                    break;
+                case CMD_START_PACKET_FILTERING:
+                    WifiNative.startPacketFiltering();
+                    break;
+                case CMD_STOP_PACKET_FILTERING:
+                    WifiNative.stopPacketFiltering();
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+        @Override
+        public void exit() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            try {
+                mBatteryStats.noteWifiStopped();
+            } catch (RemoteException ignore) { }
+        }
+    }
+
+    class DriverStoppingState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch(message.what) {
+                case DRIVER_STOP_EVENT:
+                    transitionTo(mDriverStoppedState);
+                    break;
+                    /* Queue driver commands */
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_POWER_MODE:
+                case CMD_SET_BLUETOOTH_COEXISTENCE:
+                case CMD_SET_BLUETOOTH_SCAN_MODE:
+                case CMD_SET_NUM_ALLOWED_CHANNELS:
+                case CMD_START_PACKET_FILTERING:
+                case CMD_STOP_PACKET_FILTERING:
+                    deferMessage(message);
+                    break;
+                    /* Queue the asynchronous version of these commands */
+                case CMD_START_SCAN:
+                case CMD_DISCONNECT:
+                case CMD_REASSOCIATE:
+                case CMD_RECONNECT:
+                    if (message.arg2 != SYNCHRONOUS_CALL) {
+                        deferMessage(message);
+                    }
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DriverStoppedState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            return NOT_HANDLED;
+        }
+    }
+
+    class ScanModeState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            SyncParams syncParams;
+            switch(message.what) {
+                case CMD_SET_SCAN_MODE:
+                    if (message.arg1 == SCAN_ONLY_MODE) {
+                        /* Ignore */
+                        return HANDLED;
+                    } else {
+                        WifiNative.setScanResultHandlingCommand(message.arg1);
+                        WifiNative.reconnectCommand();
+                        mIsScanMode = false;
+                        transitionTo(mDisconnectedState);
+                    }
+                    break;
+                case CMD_START_SCAN:
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = WifiNative.scanCommand(
+                                message.arg1 == SCAN_ACTIVE);
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
+                    }
+                    break;
+                    /* Ignore */
+                case CMD_DISCONNECT:
+                case CMD_RECONNECT:
+                case CMD_REASSOCIATE:
+                case SUPPLICANT_STATE_CHANGE_EVENT:
+                case NETWORK_CONNECTION_EVENT:
+                case NETWORK_DISCONNECTION_EVENT:
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class ConnectModeState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            SyncParams syncParams;
+            StateChangeResult stateChangeResult;
+            switch(message.what) {
+                case PASSWORD_MAY_BE_INCORRECT_EVENT:
+                    mPasswordKeyMayBeIncorrect = true;
+                    break;
+                case SUPPLICANT_STATE_CHANGE_EVENT:
+                    stateChangeResult = (StateChangeResult) message.obj;
+                    mSupplicantStateTracker.handleEvent(stateChangeResult);
+                    break;
+                case CMD_START_SCAN:
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = true;
+                        notifyOnMsgObject(message);
+                    }
+                    /* We need to set scan type in completed state */
+                    Message newMsg = obtainMessage();
+                    newMsg.copyFrom(message);
+                    mSupplicantStateTracker.sendMessage(newMsg);
+                    break;
+                    /* Do a redundant disconnect without transition */
+                case CMD_DISCONNECT:
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.disconnectCommand();
+                    }
+                    break;
+                case CMD_RECONNECT:
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = WifiNative.reconnectCommand();
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.reconnectCommand();
+                    }
+                    break;
+                case CMD_REASSOCIATE:
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = WifiNative.reassociateCommand();
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.reassociateCommand();
+                    }
+                    break;
+                case SCAN_RESULTS_EVENT:
+                    /* Set the scan setting back to "connect" mode */
+                    WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
+                    /* Handle scan results */
+                    return NOT_HANDLED;
+                case NETWORK_CONNECTION_EVENT:
+                    Log.d(TAG,"Network connection established");
+                    stateChangeResult = (StateChangeResult) message.obj;
+
+                    mWifiInfo.setBSSID(mLastBssid = stateChangeResult.BSSID);
+                    mWifiInfo.setNetworkId(stateChangeResult.networkId);
+                    mLastNetworkId = stateChangeResult.networkId;
+
+                    /* send event to CM & network change broadcast */
+                    setDetailedState(DetailedState.OBTAINING_IPADDR);
+                    sendNetworkStateChangeBroadcast(mLastBssid);
+
+                    transitionTo(mConnectingState);
+                    break;
+                case NETWORK_DISCONNECTION_EVENT:
+                    Log.d(TAG,"Network connection lost");
+                    handleNetworkDisconnect();
+                    transitionTo(mDisconnectedState);
+                    break;
+                case CMD_GET_RSSI:
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.intValue = WifiNative.getRssiCommand();
+                    notifyOnMsgObject(message);
+                    break;
+                case CMD_GET_RSSI_APPROX:
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.intValue = WifiNative.getRssiApproxCommand();
+                    notifyOnMsgObject(message);
+                    break;
+                case CMD_GET_LINK_SPEED:
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.intValue = WifiNative.getLinkSpeedCommand();
+                    notifyOnMsgObject(message);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class ConnectingState extends HierarchicalState {
+        boolean modifiedBluetoothCoexistenceMode;
+        int powerMode;
+        Thread mDhcpThread;
+
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+            if (!mUseStaticIp) {
+
+                mDhcpThread = null;
+                modifiedBluetoothCoexistenceMode = false;
+                powerMode = DRIVER_POWER_MODE_AUTO;
+
+                if (shouldDisableCoexistenceMode()) {
+                    /*
+                     * There are problems setting the Wi-Fi driver's power
+                     * mode to active when bluetooth coexistence mode is
+                     * enabled or sense.
+                     * <p>
+                     * We set Wi-Fi to active mode when
+                     * obtaining an IP address because we've found
+                     * compatibility issues with some routers with low power
+                     * mode.
+                     * <p>
+                     * In order for this active power mode to properly be set,
+                     * we disable coexistence mode until we're done with
+                     * obtaining an IP address.  One exception is if we
+                     * are currently connected to a headset, since disabling
+                     * coexistence would interrupt that connection.
+                     */
+                    modifiedBluetoothCoexistenceMode = true;
+
+                    // Disable the coexistence mode
+                    WifiNative.setBluetoothCoexistenceModeCommand(
+                            WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
+                }
+
+                powerMode =  WifiNative.getPowerModeCommand();
+                if (powerMode < 0) {
+                  // Handle the case where supplicant driver does not support
+                  // getPowerModeCommand.
+                    powerMode = DRIVER_POWER_MODE_AUTO;
+                }
+                if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
+                    WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);
+                }
+
+                Log.d(TAG, "DHCP request started");
+                mDhcpThread = new Thread(new Runnable() {
+                    public void run() {
+                        if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
+                            Log.d(TAG, "DHCP request succeeded");
+                            sendMessage(CMD_IP_CONFIG_SUCCESS);
+                        } else {
+                            Log.d(TAG, "DHCP request failed: " +
+                                    NetworkUtils.getDhcpError());
+                            sendMessage(CMD_IP_CONFIG_FAILURE);
+                        }
+                    }
+                });
+                mDhcpThread.start();
+            } else {
+                if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {
+                    Log.v(TAG, "Static IP configuration succeeded");
+                    sendMessage(CMD_IP_CONFIG_SUCCESS);
+                } else {
+                    Log.v(TAG, "Static IP configuration failed");
+                    sendMessage(CMD_IP_CONFIG_FAILURE);
+                }
+            }
+         }
+      @Override
+      public boolean processMessage(Message message) {
+          if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+
+          switch(message.what) {
+              case CMD_IP_CONFIG_SUCCESS:
+                  mReconnectCount = 0;
+                  mLastSignalLevel = -1; // force update of signal strength
+                  mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
+                  Log.d(TAG, "IP configuration: " + mDhcpInfo);
+                  configureNetworkProperties();
+                  setDetailedState(DetailedState.CONNECTED);
+                  sendNetworkStateChangeBroadcast(mLastBssid);
+                  //TODO: we could also detect an IP config change
+                  // from a DHCP renewal and send out a config change
+                  // broadcast
+                  if (mConfigChanged) {
+                      sendConfigChangeBroadcast();
+                      mConfigChanged = false;
+                  }
+                  transitionTo(mConnectedState);
+                  break;
+              case CMD_IP_CONFIG_FAILURE:
+                  mWifiInfo.setIpAddress(0);
+
+                  Log.e(TAG, "IP configuration failed");
+                  /**
+                   * If we've exceeded the maximum number of retries for DHCP
+                   * to a given network, disable the network
+                   */
+                  if (++mReconnectCount > getMaxDhcpRetries()) {
+                          Log.e(TAG, "Failed " +
+                                  mReconnectCount + " times, Disabling " + mLastNetworkId);
+                      WifiNative.disableNetworkCommand(mLastNetworkId);
+                  }
+
+                  /* DHCP times out after about 30 seconds, we do a
+                   * disconnect and an immediate reconnect to try again
+                   */
+                  WifiNative.disconnectCommand();
+                  WifiNative.reconnectCommand();
+                  transitionTo(mDisconnectingState);
+                  break;
+              case CMD_DISCONNECT:
+                  if (message.arg2 == SYNCHRONOUS_CALL) {
+                      SyncParams syncParams = (SyncParams) message.obj;
+                      syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
+                      notifyOnMsgObject(message);
+                  } else {
+                      /* asynchronous handling */
+                      WifiNative.disconnectCommand();
+                  }
+                  transitionTo(mDisconnectingState);
+                  break;
+                  /* Ignore */
+              case NETWORK_CONNECTION_EVENT:
+                  break;
+              case CMD_STOP_DRIVER:
+                  sendMessage(CMD_DISCONNECT);
+                  deferMessage(message);
+                  break;
+              case CMD_SET_SCAN_MODE:
+                  if (message.arg1 == SCAN_ONLY_MODE) {
+                      sendMessage(CMD_DISCONNECT);
+                      deferMessage(message);
+                  }
+                  break;
+              case CMD_RECONFIGURE_IP:
+                  deferMessage(message);
+                  break;
+              default:
+                return NOT_HANDLED;
+          }
+          EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+          return HANDLED;
+      }
+
+      @Override
+      public void exit() {
+          /* reset power state & bluetooth coexistence if on DHCP */
+          if (!mUseStaticIp) {
+              if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
+                  WifiNative.setPowerModeCommand(powerMode);
+              }
+
+              if (modifiedBluetoothCoexistenceMode) {
+                  // Set the coexistence mode back to its default value
+                  WifiNative.setBluetoothCoexistenceModeCommand(
+                          WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
+              }
+          }
+
+      }
+    }
+
+    class ConnectedState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_DISCONNECT:
+                    if (message.arg2 == SYNCHRONOUS_CALL) {
+                        SyncParams syncParams = (SyncParams) message.obj;
+                        syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
+                        notifyOnMsgObject(message);
+                    } else {
+                        /* asynchronous handling */
+                        WifiNative.disconnectCommand();
+                    }
+                    transitionTo(mDisconnectingState);
+                    break;
+                case CMD_RECONFIGURE_IP:
+                    Log.d(TAG,"Reconfiguring IP on connection");
+                    NetworkUtils.resetConnections(mInterfaceName);
+                    transitionTo(mConnectingState);
+                    break;
+                case CMD_STOP_DRIVER:
+                    sendMessage(CMD_DISCONNECT);
+                    deferMessage(message);
+                    break;
+                case CMD_SET_SCAN_MODE:
+                    if (message.arg1 == SCAN_ONLY_MODE) {
+                        sendMessage(CMD_DISCONNECT);
+                        deferMessage(message);
+                    }
+                    break;
+                    /* Ignore */
+                case NETWORK_CONNECTION_EVENT:
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DisconnectingState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */
+                    deferMessage(message);
+                    break;
+                case CMD_SET_SCAN_MODE:
+                    if (message.arg1 == SCAN_ONLY_MODE) {
+                        deferMessage(message);
+                    }
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class DisconnectedState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_SET_SCAN_MODE:
+                    if (message.arg1 == SCAN_ONLY_MODE) {
+                        WifiNative.setScanResultHandlingCommand(message.arg1);
+                        //Supplicant disconnect to prevent further connects
+                        WifiNative.disconnectCommand();
+                        mIsScanMode = true;
+                        transitionTo(mScanModeState);
+                    }
+                    break;
+                    /* Ignore network disconnect */
+                case NETWORK_DISCONNECTION_EVENT:
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+    class SoftApStartedState extends HierarchicalState {
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch(message.what) {
+                case CMD_STOP_AP:
+                    Log.d(TAG,"Stopping Soft AP");
+                    setWifiApState(WIFI_AP_STATE_DISABLING);
+                    try {
+                        nwService.stopAccessPoint();
+                    } catch(Exception e) {
+                        Log.e(TAG, "Exception in stopAccessPoint()");
+                    }
+                    transitionTo(mDriverLoadedState);
+                    break;
+                case CMD_START_AP:
+                    Log.d(TAG,"SoftAP set on a running access point");
+                    try {
+                        nwService.setAccessPoint((WifiConfiguration) message.obj,
+                                    mInterfaceName,
+                                    SOFTAP_IFACE);
+                    } catch(Exception e) {
+                        Log.e(TAG, "Exception in nwService during soft AP set");
+                        try {
+                            nwService.stopAccessPoint();
+                        } catch (Exception ee) {
+                            Slog.e(TAG, "Could not stop AP, :" + ee);
+                        }
+                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
+                    }
+                    break;
+                /* Fail client mode operation when soft AP is enabled */
+                case CMD_START_SUPPLICANT:
+                    Log.e(TAG,"Cannot start supplicant with a running soft AP");
+                    setWifiState(WIFI_STATE_UNKNOWN);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
+            return HANDLED;
+        }
+    }
+
+
+    class SupplicantStateTracker extends HierarchicalStateMachine {
+
+        private int mRssiPollToken = 0;
+
+        /**
+         * The max number of the WPA supplicant loop iterations before we
+         * decide that the loop should be terminated:
+         */
+        private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4;
+        private int mLoopDetectIndex = 0;
+        private int mLoopDetectCount = 0;
+
+        /**
+         *  Supplicant state change commands follow
+         *  the ordinal values defined in SupplicantState.java
+         */
+        private static final int DISCONNECTED           = 0;
+        private static final int INACTIVE               = 1;
+        private static final int SCANNING               = 2;
+        private static final int ASSOCIATING            = 3;
+        private static final int ASSOCIATED             = 4;
+        private static final int FOUR_WAY_HANDSHAKE     = 5;
+        private static final int GROUP_HANDSHAKE        = 6;
+        private static final int COMPLETED              = 7;
+        private static final int DORMANT                = 8;
+        private static final int UNINITIALIZED          = 9;
+        private static final int INVALID                = 10;
+
+        private HierarchicalState mUninitializedState = new UninitializedState();
+        private HierarchicalState mInitializedState = new InitializedState();;
+        private HierarchicalState mInactiveState = new InactiveState();
+        private HierarchicalState mDisconnectState = new DisconnectedState();
+        private HierarchicalState mScanState = new ScanState();
+        private HierarchicalState mConnectState = new ConnectState();
+        private HierarchicalState mHandshakeState = new HandshakeState();
+        private HierarchicalState mCompletedState = new CompletedState();
+        private HierarchicalState mDormantState = new DormantState();
+
+        public SupplicantStateTracker(Context context, Handler target) {
+            super(TAG, target.getLooper());
+
+            addState(mUninitializedState);
+            addState(mInitializedState);
+                addState(mInactiveState, mInitializedState);
+                addState(mDisconnectState, mInitializedState);
+                addState(mScanState, mInitializedState);
+                addState(mConnectState, mInitializedState);
+                    addState(mHandshakeState, mConnectState);
+                    addState(mCompletedState, mConnectState);
+                addState(mDormantState, mInitializedState);
+
+            setInitialState(mUninitializedState);
+
+            //start the state machine
+            start();
+        }
+
+        public void handleEvent(StateChangeResult stateChangeResult) {
+            SupplicantState newState = (SupplicantState) stateChangeResult.state;
+
+            // Supplicant state change
+            // [31-13] Reserved for future use
+            // [8 - 0] Supplicant state (as defined in SupplicantState.java)
+            // 50023 supplicant_state_changed (custom|1|5)
+            EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, newState.ordinal());
+
+            sendMessage(obtainMessage(newState.ordinal(), stateChangeResult));
+        }
+
+        public void resetSupplicantState() {
+            transitionTo(mUninitializedState);
+        }
+
+        private void resetLoopDetection() {
+            mLoopDetectCount = 0;
+            mLoopDetectIndex = 0;
+        }
+
+        private boolean handleTransition(Message msg) {
+            if (DBG) Log.d(TAG, getName() + msg.toString() + "\n");
+            switch (msg.what) {
+                case DISCONNECTED:
+                    transitionTo(mDisconnectState);
+                    break;
+                case SCANNING:
+                    transitionTo(mScanState);
+                    break;
+                case ASSOCIATING:
+                    StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
+                    /* BSSID is valid only in ASSOCIATING state */
+                    mWifiInfo.setBSSID(stateChangeResult.BSSID);
+                    //$FALL-THROUGH$
+                case ASSOCIATED:
+                case FOUR_WAY_HANDSHAKE:
+                case GROUP_HANDSHAKE:
+                    transitionTo(mHandshakeState);
+                    break;
+                case COMPLETED:
+                    transitionTo(mCompletedState);
+                    break;
+                case DORMANT:
+                    transitionTo(mDormantState);
+                    break;
+                case INACTIVE:
+                    transitionTo(mInactiveState);
+                    break;
+                case UNINITIALIZED:
+                case INVALID:
+                    transitionTo(mUninitializedState);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
+            SupplicantState supState = (SupplicantState) stateChangeResult.state;
+            setDetailedState(WifiInfo.getDetailedStateOf(supState));
+            mWifiInfo.setSupplicantState(supState);
+            mWifiInfo.setNetworkId(stateChangeResult.networkId);
+            //TODO: Modify WifiMonitor to report SSID on events
+            //mWifiInfo.setSSID()
+            return HANDLED;
+        }
+
+        /********************************************************
+         * HSM states
+         *******************************************************/
+
+        class InitializedState extends HierarchicalState {
+            @Override
+             public void enter() {
+                 if (DBG) Log.d(TAG, getName() + "\n");
+             }
+            @Override
+            public boolean processMessage(Message message) {
+                if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+                switch (message.what) {
+                    case CMD_START_SCAN:
+                        WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
+                        break;
+                    default:
+                        if (DBG) Log.w(TAG, "Ignoring " + message);
+                        break;
+                }
+                return HANDLED;
+            }
+        }
+
+        class UninitializedState extends HierarchicalState {
+            @Override
+             public void enter() {
+                 if (DBG) Log.d(TAG, getName() + "\n");
+                 mNetworkInfo.setIsAvailable(false);
+                 resetLoopDetection();
+                 mPasswordKeyMayBeIncorrect = false;
+             }
+            @Override
+            public boolean processMessage(Message message) {
+                switch(message.what) {
+                    default:
+                        if (!handleTransition(message)) {
+                            if (DBG) Log.w(TAG, "Ignoring " + message);
+                        }
+                        break;
+                }
+                return HANDLED;
+            }
+            @Override
+            public void exit() {
+                mNetworkInfo.setIsAvailable(true);
+            }
+        }
+
+        class InactiveState extends HierarchicalState {
+            @Override
+             public void enter() {
+                 if (DBG) Log.d(TAG, getName() + "\n");
+                 Message message = getCurrentMessage();
+                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+                 mNetworkInfo.setIsAvailable(false);
+                 resetLoopDetection();
+                 mPasswordKeyMayBeIncorrect = false;
+
+                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+             }
+            @Override
+            public boolean processMessage(Message message) {
+                return handleTransition(message);
+            }
+            @Override
+            public void exit() {
+                mNetworkInfo.setIsAvailable(true);
+            }
+        }
+
+
+        class DisconnectedState extends HierarchicalState {
+            @Override
+             public void enter() {
+                 if (DBG) Log.d(TAG, getName() + "\n");
+                 Message message = getCurrentMessage();
+                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+                 resetLoopDetection();
+
+                 /* If a disconnect event happens after a password key failure
+                  * event, disable the network
+                  */
+                 if (mPasswordKeyMayBeIncorrect) {
+                     Log.d(TAG, "Failed to authenticate, disabling network " +
+                             mWifiInfo.getNetworkId());
+                     WifiNative.disableNetworkCommand(mWifiInfo.getNetworkId());
+                     mPasswordKeyMayBeIncorrect = false;
+                     sendSupplicantStateChangedBroadcast(stateChangeResult, true);
+                 }
+                 else {
+                     sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+                 }
+             }
+            @Override
+            public boolean processMessage(Message message) {
+                return handleTransition(message);
+            }
+        }
+
+        class ScanState extends HierarchicalState {
+            @Override
+             public void enter() {
+                 if (DBG) Log.d(TAG, getName() + "\n");
+                 Message message = getCurrentMessage();
+                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+                 mPasswordKeyMayBeIncorrect = false;
+                 resetLoopDetection();
+                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+             }
+            @Override
+            public boolean processMessage(Message message) {
+                return handleTransition(message);
+            }
+        }
+
+        class ConnectState extends HierarchicalState {
+            @Override
+             public void enter() {
+                 if (DBG) Log.d(TAG, getName() + "\n");
+             }
+            @Override
+            public boolean processMessage(Message message) {
+                switch (message.what) {
+                    case CMD_START_SCAN:
+                        WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
+                        WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
+                        break;
+                    default:
+                        return NOT_HANDLED;
+                }
+                return HANDLED;
+            }
+        }
+
+        class HandshakeState extends HierarchicalState {
+            @Override
+             public void enter() {
+                 if (DBG) Log.d(TAG, getName() + "\n");
+                 final Message message = getCurrentMessage();
+                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+                 if (mLoopDetectIndex > message.what) {
+                     mLoopDetectCount++;
+                 }
+                 if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) {
+                     WifiNative.disableNetworkCommand(stateChangeResult.networkId);
+                     mLoopDetectCount = 0;
+                 }
+
+                 mLoopDetectIndex = message.what;
+
+                 mPasswordKeyMayBeIncorrect = false;
+                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+             }
+            @Override
+            public boolean processMessage(Message message) {
+                return handleTransition(message);
+            }
+        }
+
+        class CompletedState extends HierarchicalState {
+            @Override
+             public void enter() {
+                 if (DBG) Log.d(TAG, getName() + "\n");
+                 Message message = getCurrentMessage();
+                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+                 mRssiPollToken++;
+                 if (mEnableRssiPolling) {
+                     sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
+                             POLL_RSSI_INTERVAL_MSECS);
+                 }
+
+                 resetLoopDetection();
+
+                 mPasswordKeyMayBeIncorrect = false;
+                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+             }
+            @Override
+            public boolean processMessage(Message message) {
+                switch(message.what) {
+                    case ASSOCIATING:
+                    case ASSOCIATED:
+                    case FOUR_WAY_HANDSHAKE:
+                    case GROUP_HANDSHAKE:
+                    case COMPLETED:
+                        break;
+                    case CMD_RSSI_POLL:
+                        if (message.arg1 == mRssiPollToken) {
+                            // Get Info and continue polling
+                            requestPolledInfo();
+                            sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
+                                    POLL_RSSI_INTERVAL_MSECS);
+                        } else {
+                            // Polling has completed
+                        }
+                        break;
+                    case CMD_ENABLE_RSSI_POLL:
+                        mRssiPollToken++;
+                        if (mEnableRssiPolling) {
+                            // first poll
+                            requestPolledInfo();
+                            sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
+                                    POLL_RSSI_INTERVAL_MSECS);
+                        }
+                        break;
+                    default:
+                        return handleTransition(message);
+                }
+                return HANDLED;
+            }
+        }
+
+        class DormantState extends HierarchicalState {
+            @Override
+            public void enter() {
+                if (DBG) Log.d(TAG, getName() + "\n");
+                Message message = getCurrentMessage();
+                StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+
+                resetLoopDetection();
+                mPasswordKeyMayBeIncorrect = false;
+
+                sendSupplicantStateChangedBroadcast(stateChangeResult, false);
+
+                /* TODO: reconnect is now being handled at DHCP failure handling
+                 * If we run into issues with staying in Dormant state, might
+                 * need a reconnect here
+                 */
+            }
+            @Override
+            public boolean processMessage(Message message) {
+                return handleTransition(message);
+            }
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 388beea..8e1b236 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -16,524 +16,59 @@
 
 package android.net.wifi;
 
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
-import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
 
-/**
- * TODO: Add soft AP states as part of WIFI_STATE_XXX
- * Retain WIFI_STATE_ENABLING that indicates driver is loading
- * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started
- * and WIFI_STATE_FAILED for failure
- * Deprecate WIFI_STATE_UNKNOWN
- *
- * Doing this will simplify the logic for sending broadcasts
- */
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
 
-import android.app.ActivityManagerNative;
-import android.net.NetworkInfo;
-import android.net.NetworkStateTracker;
-import android.net.DhcpInfo;
-import android.net.NetworkUtils;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
-import android.net.NetworkProperties;
-import android.os.Binder;
-import android.os.Message;
-import android.os.Parcelable;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.PowerManager;
-import android.os.SystemProperties;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.Process;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.Slog;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.backup.IBackupManager;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothA2dp;
-import android.content.ContentResolver;
-import android.content.Intent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.database.ContentObserver;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkProperties;
+import android.net.NetworkStateTracker;
+import android.os.Handler;
+import android.os.Message;
 
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Pattern;
 
 /**
- * Track the state of Wifi connectivity. All event handling is done here,
- * and all changes in connectivity state are initiated here.
+ * Track the state of wifi for connectivity service.
  *
  * @hide
  */
-//TODO: we still need frequent scanning for the case when
-// we issue disconnect but need scan results for open network notification
-public class WifiStateTracker extends HierarchicalStateMachine implements NetworkStateTracker {
+public class WifiStateTracker implements NetworkStateTracker {
 
-    private static final String TAG = "WifiStateTracker";
     private static final String NETWORKTYPE = "WIFI";
-    private static final boolean DBG = false;
+    private static final String TAG = "WifiStateTracker";
 
-    /* TODO: fetch a configurable interface */
-    private static final String SOFTAP_IFACE = "wl0.1";
-
-    private WifiMonitor mWifiMonitor;
-    private INetworkManagementService nwService;
-    private ConnectivityManager mCm;
-
-    /* Scan results handling */
-    private List<ScanResult> mScanResults;
-    private static final Pattern scanResultPattern = Pattern.compile("\t+");
-    private static final int SCAN_RESULT_CACHE_SIZE = 80;
-    private final LinkedHashMap<String, ScanResult> mScanResultCache;
-
-    private String mInterfaceName;
     private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
     private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
     private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
 
-    private int mNumAllowedChannels = 0;
-    private int mLastSignalLevel = -1;
-    private String mLastBssid;
-    private int mLastNetworkId;
-    private boolean mEnableRssiPolling = false;
-    private boolean mPasswordKeyMayBeIncorrect = false;
-    private boolean mUseStaticIp = false;
-    private int mReconnectCount = 0;
-    private boolean mIsScanMode = false;
-
-    /**
-     * Instance of the bluetooth headset helper. This needs to be created
-     * early because there is a delay before it actually 'connects', as
-     * noted by its javadoc. If we check before it is connected, it will be
-     * in an error state and we will not disable coexistence.
-     */
-    private BluetoothHeadset mBluetoothHeadset;
-
-    private BluetoothA2dp mBluetoothA2dp;
-
-    /**
-     * Observes the static IP address settings.
-     */
-    private SettingsObserver mSettingsObserver;
     private NetworkProperties mNetworkProperties;
-
-
-    // Variables relating to the 'available networks' notification
-    /**
-     * The icon to show in the 'available networks' notification. This will also
-     * be the ID of the Notification given to the NotificationManager.
-     */
-    private static final int ICON_NETWORKS_AVAILABLE =
-            com.android.internal.R.drawable.stat_notify_wifi_in_range;
-    /**
-     * When a notification is shown, we wait this amount before possibly showing it again.
-     */
-    private final long NOTIFICATION_REPEAT_DELAY_MS;
-    /**
-     * Whether the user has set the setting to show the 'available networks' notification.
-     */
-    private boolean mNotificationEnabled;
-    /**
-     * Observes the user setting to keep {@link #mNotificationEnabled} in sync.
-     */
-    private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver;
-    /**
-     * The {@link System#currentTimeMillis()} must be at least this value for us
-     * to show the notification again.
-     */
-    private long mNotificationRepeatTime;
-    /**
-     * The Notification object given to the NotificationManager.
-     */
-    private Notification mNotification;
-    /**
-     * Whether the notification is being shown, as set by us. That is, if the
-     * user cancels the notification, we will not receive the callback so this
-     * will still be true. We only guarantee if this is false, then the
-     * notification is not showing.
-     */
-    private boolean mNotificationShown;
-    /**
-     * The number of continuous scans that must occur before consider the
-     * supplicant in a scanning state. This allows supplicant to associate with
-     * remembered networks that are in the scan results.
-     */
-    private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3;
-    /**
-     * The number of scans since the last network state change. When this
-     * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the
-     * supplicant to actually be scanning. When the network state changes to
-     * something other than scanning, we reset this to 0.
-     */
-    private int mNumScansSinceNetworkStateChange;
-
-    // Held during driver load and unload
-    private static PowerManager.WakeLock sWakeLock;
+    private NetworkInfo mNetworkInfo;
 
     /* For sending events to connectivity service handler */
     private Handler mCsHandler;
     private Context mContext;
-
-    private DhcpInfo mDhcpInfo;
-    private WifiInfo mWifiInfo;
-    private NetworkInfo mNetworkInfo;
-    private SupplicantStateTracker mSupplicantStateTracker;
-
-    // Event log tags (must be in sync with event-log-tags)
-    private static final int EVENTLOG_WIFI_STATE_CHANGED        = 50021;
-    private static final int EVENTLOG_WIFI_EVENT_HANDLED        = 50022;
-    private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED  = 50023;
-
-    /* Load the driver */
-    private static final int CMD_LOAD_DRIVER                      = 1;
-    /* Unload the driver */
-    private static final int CMD_UNLOAD_DRIVER                    = 2;
-    /* Indicates driver load succeeded */
-    private static final int CMD_LOAD_DRIVER_SUCCESS              = 3;
-    /* Indicates driver load failed */
-    private static final int CMD_LOAD_DRIVER_FAILURE              = 4;
-    /* Indicates driver unload succeeded */
-    private static final int CMD_UNLOAD_DRIVER_SUCCESS            = 5;
-    /* Indicates driver unload failed */
-    private static final int CMD_UNLOAD_DRIVER_FAILURE            = 6;
-
-    /* Start the supplicant */
-    private static final int CMD_START_SUPPLICANT                 = 11;
-    /* Stop the supplicant */
-    private static final int CMD_STOP_SUPPLICANT                  = 12;
-    /* Start the driver */
-    private static final int CMD_START_DRIVER                     = 13;
-    /* Start the driver */
-    private static final int CMD_STOP_DRIVER                      = 14;
-    /* Indicates DHCP succeded */
-    private static final int CMD_IP_CONFIG_SUCCESS                = 15;
-    /* Indicates DHCP failed */
-    private static final int CMD_IP_CONFIG_FAILURE                = 16;
-    /* Re-configure interface */
-    private static final int CMD_RECONFIGURE_IP                   = 17;
-
-
-    /* Start the soft access point */
-    private static final int CMD_START_AP                         = 21;
-    /* Stop the soft access point */
-    private static final int CMD_STOP_AP                          = 22;
-
-
-    /* Supplicant events */
-    /* Connection to supplicant established */
-    private static final int SUP_CONNECTION_EVENT                 = 31;
-    /* Connection to supplicant lost */
-    private static final int SUP_DISCONNECTION_EVENT              = 32;
-    /* Driver start completed */
-    private static final int DRIVER_START_EVENT                   = 33;
-    /* Driver stop completed */
-    private static final int DRIVER_STOP_EVENT                    = 34;
-    /* Network connection completed */
-    private static final int NETWORK_CONNECTION_EVENT             = 36;
-    /* Network disconnection completed */
-    private static final int NETWORK_DISCONNECTION_EVENT          = 37;
-    /* Scan results are available */
-    private static final int SCAN_RESULTS_EVENT                   = 38;
-    /* Supplicate state changed */
-    private static final int SUPPLICANT_STATE_CHANGE_EVENT        = 39;
-    /* Password may be incorrect */
-    private static final int PASSWORD_MAY_BE_INCORRECT_EVENT      = 40;
-
-    /* Supplicant commands */
-    /* Is supplicant alive ? */
-    private static final int CMD_PING_SUPPLICANT                  = 51;
-    /* Add/update a network configuration */
-    private static final int CMD_ADD_OR_UPDATE_NETWORK            = 52;
-    /* Delete a network */
-    private static final int CMD_REMOVE_NETWORK                   = 53;
-    /* Enable a network. The device will attempt a connection to the given network. */
-    private static final int CMD_ENABLE_NETWORK                   = 54;
-    /* Disable a network. The device does not attempt a connection to the given network. */
-    private static final int CMD_DISABLE_NETWORK                  = 55;
-    /* Blacklist network. De-prioritizes the given BSSID for connection. */
-    private static final int CMD_BLACKLIST_NETWORK                = 56;
-    /* Clear the blacklist network list */
-    private static final int CMD_CLEAR_BLACKLIST                  = 57;
-    /* Get the configured networks */
-    private static final int CMD_GET_NETWORK_CONFIG               = 58;
-    /* Save configuration */
-    private static final int CMD_SAVE_CONFIG                      = 59;
-    /* Connection status */
-    private static final int CMD_CONNECTION_STATUS                = 60;
-
-    /* Supplicant commands after driver start*/
-    /* Initiate a scan */
-    private static final int CMD_START_SCAN                       = 71;
-    /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
-    private static final int CMD_SET_SCAN_MODE                    = 72;
-    /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */
-    private static final int CMD_SET_SCAN_TYPE                    = 73;
-    /* Disconnect from a network */
-    private static final int CMD_DISCONNECT                       = 74;
-    /* Reconnect to a network */
-    private static final int CMD_RECONNECT                        = 75;
-    /* Reassociate to a network */
-    private static final int CMD_REASSOCIATE                      = 76;
-    /* Set power mode
-     * POWER_MODE_ACTIVE
-     * POWER_MODE_AUTO
-     */
-    private static final int CMD_SET_POWER_MODE                   = 77;
-    /* Set bluetooth co-existence
-     * BLUETOOTH_COEXISTENCE_MODE_ENABLED
-     * BLUETOOTH_COEXISTENCE_MODE_DISABLED
-     * BLUETOOTH_COEXISTENCE_MODE_SENSE
-     */
-    private static final int CMD_SET_BLUETOOTH_COEXISTENCE        = 78;
-    /* Enable/disable bluetooth scan mode
-     * true(1)
-     * false(0)
-     */
-    private static final int CMD_SET_BLUETOOTH_SCAN_MODE          = 79;
-    /* Set number of allowed channels */
-    private static final int CMD_SET_NUM_ALLOWED_CHANNELS         = 80;
-    /* Request connectivity manager wake lock before driver stop */
-    private static final int CMD_REQUEST_CM_WAKELOCK              = 81;
-    /* Enables RSSI poll */
-    private static final int CMD_ENABLE_RSSI_POLL                 = 82;
-    /* RSSI poll */
-    private static final int CMD_RSSI_POLL                        = 83;
-    /* Get current RSSI */
-    private static final int CMD_GET_RSSI                         = 84;
-    /* Get approx current RSSI */
-    private static final int CMD_GET_RSSI_APPROX                  = 85;
-    /* Get link speed on connection */
-    private static final int CMD_GET_LINK_SPEED                   = 86;
-    /* Radio mac address */
-    private static final int CMD_GET_MAC_ADDR                     = 87;
-    /* Set up packet filtering */
-    private static final int CMD_START_PACKET_FILTERING           = 88;
-    /* Clear packet filter */
-    private static final int CMD_STOP_PACKET_FILTERING            = 89;
-
-    /* Connectivity service commands */
-    /* Bring down wifi connection */
-    private static final int CM_CMD_TEARDOWN                      = 110;
-    /* Reconnect to wifi */
-    private static final int CM_CMD_RECONNECT                     = 111;
-
-    /**
-     * Interval in milliseconds between polling for connection
-     * status items that are not sent via asynchronous events.
-     * An example is RSSI (signal strength).
-     */
-    private static final int POLL_RSSI_INTERVAL_MSECS = 3000;
-
-    private static final int CONNECT_MODE   = 1;
-    private static final int SCAN_ONLY_MODE = 2;
-
-    private static final int SCAN_ACTIVE = 1;
-    private static final int SCAN_PASSIVE = 2;
-
-    /**
-     * The maximum number of times we will retry a connection to an access point
-     * for which we have failed in acquiring an IP address from DHCP. A value of
-     * N means that we will make N+1 connection attempts in all.
-     * <p>
-     * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default
-     * value if a Settings value is not present.
-     */
-    private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
-
-    private static final int DRIVER_POWER_MODE_ACTIVE = 1;
-    private static final int DRIVER_POWER_MODE_AUTO = 0;
-
-    /* Default parent state */
-    private HierarchicalState mDefaultState = new DefaultState();
-    /* Temporary initial state */
-    private HierarchicalState mInitialState = new InitialState();
-    /* Unloading the driver */
-    private HierarchicalState mDriverUnloadingState = new DriverUnloadingState();
-    /* Loading the driver */
-    private HierarchicalState mDriverUnloadedState = new DriverUnloadedState();
-    /* Driver load/unload failed */
-    private HierarchicalState mDriverFailedState = new DriverFailedState();
-    /* Driver loading */
-    private HierarchicalState mDriverLoadingState = new DriverLoadingState();
-    /* Driver loaded */
-    private HierarchicalState mDriverLoadedState = new DriverLoadedState();
-    /* Driver loaded, waiting for supplicant to start */
-    private HierarchicalState mWaitForSupState = new WaitForSupState();
-
-    /* Driver loaded and supplicant ready */
-    private HierarchicalState mDriverSupReadyState = new DriverSupReadyState();
-    /* Driver start issued, waiting for completed event */
-    private HierarchicalState mDriverStartingState = new DriverStartingState();
-    /* Driver started */
-    private HierarchicalState mDriverStartedState = new DriverStartedState();
-    /* Driver stopping */
-    private HierarchicalState mDriverStoppingState = new DriverStoppingState();
-    /* Driver stopped */
-    private HierarchicalState mDriverStoppedState = new DriverStoppedState();
-    /* Scan for networks, no connection will be established */
-    private HierarchicalState mScanModeState = new ScanModeState();
-    /* Connecting to an access point */
-    private HierarchicalState mConnectModeState = new ConnectModeState();
-    /* Fetching IP after network connection (assoc+auth complete) */
-    private HierarchicalState mConnectingState = new ConnectingState();
-    /* Connected with IP addr */
-    private HierarchicalState mConnectedState = new ConnectedState();
-    /* disconnect issued, waiting for network disconnect confirmation */
-    private HierarchicalState mDisconnectingState = new DisconnectingState();
-    /* Network is not connected, supplicant assoc+auth is not complete */
-    private HierarchicalState mDisconnectedState = new DisconnectedState();
-
-    /* Soft Ap is running */
-    private HierarchicalState mSoftApStartedState = new SoftApStartedState();
-
-    /* Argument for Message object to indicate a synchronous call */
-    private static final int SYNCHRONOUS_CALL = 1;
-    private static final int ASYNCHRONOUS_CALL = 0;
-
-
-    /**
-     * One of  {@link WifiManager#WIFI_STATE_DISABLED},
-     *         {@link WifiManager#WIFI_STATE_DISABLING},
-     *         {@link WifiManager#WIFI_STATE_ENABLED},
-     *         {@link WifiManager#WIFI_STATE_ENABLING},
-     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
-     *
-     */
-    private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
-
-    /**
-     * One of  {@link WifiManager#WIFI_AP_STATE_DISABLED},
-     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
-     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
-     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
-     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
-     *
-     */
-    private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
-
-    private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
-    private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
-
-    private final IBatteryStats mBatteryStats;
+    private BroadcastReceiver mWifiStateReceiver;
+    private WifiManager mWifiManager;
 
     public WifiStateTracker(Context context, Handler target) {
-        super(NETWORKTYPE);
-
         mCsHandler = target;
         mContext = context;
 
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
-        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
-
-        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
-        nwService = INetworkManagementService.Stub.asInterface(b);
-
-        mWifiMonitor = new WifiMonitor(this);
-        mDhcpInfo = new DhcpInfo();
-        mWifiInfo = new WifiInfo();
-        mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0");
-        mSupplicantStateTracker = new SupplicantStateTracker(context, getHandler());
-
-        mBluetoothHeadset = new BluetoothHeadset(mContext, null);
         mNetworkProperties = new NetworkProperties();
 
         mNetworkInfo.setIsAvailable(false);
         mNetworkProperties.clear();
-        resetNotificationTimer();
         setTeardownRequested(false);
-        mLastBssid = null;
-        mLastNetworkId = -1;
-        mLastSignalLevel = -1;
-
-        mScanResultCache = new LinkedHashMap<String, ScanResult>(
-            SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
-                /*
-                 * Limit the cache size by SCAN_RESULT_CACHE_SIZE
-                 * elements
-                 */
-                @Override
-                public boolean removeEldestEntry(Map.Entry eldest) {
-                    return SCAN_RESULT_CACHE_SIZE < this.size();
-                }
-        };
-
-        // Setting is in seconds
-        NOTIFICATION_REPEAT_DELAY_MS = Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l;
-        mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(target);
-        mNotificationEnabledSettingObserver.register();
-
-        mSettingsObserver = new SettingsObserver(new Handler());
-
-        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
-        addState(mDefaultState);
-            addState(mInitialState, mDefaultState);
-            addState(mDriverUnloadingState, mDefaultState);
-            addState(mDriverUnloadedState, mDefaultState);
-                addState(mDriverFailedState, mDriverUnloadedState);
-            addState(mDriverLoadingState, mDefaultState);
-            addState(mDriverLoadedState, mDefaultState);
-                addState(mWaitForSupState, mDriverLoadedState);
-            addState(mDriverSupReadyState, mDefaultState);
-                addState(mDriverStartingState, mDriverSupReadyState);
-                addState(mDriverStartedState, mDriverSupReadyState);
-                    addState(mScanModeState, mDriverStartedState);
-                    addState(mConnectModeState, mDriverStartedState);
-                        addState(mConnectingState, mConnectModeState);
-                        addState(mConnectedState, mConnectModeState);
-                        addState(mDisconnectingState, mConnectModeState);
-                        addState(mDisconnectedState, mConnectModeState);
-                addState(mDriverStoppingState, mDriverSupReadyState);
-                addState(mDriverStoppedState, mDriverSupReadyState);
-            addState(mSoftApStartedState, mDefaultState);
-
-        setInitialState(mInitialState);
-
-        if (DBG) setDbg(true);
-
-        //start the state machine
-        start();
     }
 
 
-    /*********************************************************
-     * NetworkStateTracker interface implementation
-     ********************************************************/
-
     public void setTeardownRequested(boolean isRequested) {
         mTeardownRequested.set(isRequested);
     }
@@ -544,11 +79,17 @@
 
     /**
      * Begin monitoring wifi connectivity
-     * @deprecated
-     *
-     * TODO: remove this from callers
      */
     public void startMonitoring() {
+        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.CONFIG_CHANGED_ACTION);
+        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+
+        mWifiStateReceiver = new WifiStateReceiver();
+        mContext.registerReceiver(mWifiStateReceiver, filter);
     }
 
     /**
@@ -556,7 +97,8 @@
      * TODO: do away with return value after making MobileDataStateTracker async
      */
     public boolean teardown() {
-        sendMessage(CM_CMD_TEARDOWN);
+        mTeardownRequested.set(true);
+        mWifiManager.stopWifi();
         return true;
     }
 
@@ -565,7 +107,8 @@
      * TODO: do away with return value after making MobileDataStateTracker async
      */
     public boolean reconnect() {
-        sendMessage(CM_CMD_RECONNECT);
+        mTeardownRequested.set(false);
+        mWifiManager.startWifi();
         return true;
     }
 
@@ -575,7 +118,7 @@
      * TODO: do away with return value after making MobileDataStateTracker async
      */
     public boolean setRadio(boolean turnOn) {
-        setWifiEnabled(turnOn);
+        mWifiManager.setWifiEnabled(turnOn);
         return true;
     }
 
@@ -626,21 +169,6 @@
         return -1;
     }
 
-    /* TODO: will go away.
-     * Notifications are directly handled in WifiStateTracker at checkAndSetNotification()
-     */
-    public void interpretScanResultsAvailable() {
-
-    }
-
-    /**
-     * Return the name of our WLAN network interface.
-     * @return the name of our interface.
-     */
-    public String getInterfaceName() {
-        return mInterfaceName;
-    }
-
     /**
      * Check if private DNS route is set for the network
      */
@@ -698,3279 +226,23 @@
         return "net.tcp.buffersize.wifi";
     }
 
-
-    /*********************************************************
-     * Methods exposed for public use
-     ********************************************************/
-
-    /**
-     * TODO: doc
-     */
-    public boolean pingSupplicant() {
-        return sendSyncMessage(CMD_PING_SUPPLICANT).boolValue;
-    }
-
-    /**
-     * TODO: doc
-     */
-    public boolean startScan(boolean forceActive) {
-        return sendSyncMessage(obtainMessage(CMD_START_SCAN, forceActive ?
-                SCAN_ACTIVE : SCAN_PASSIVE, 0)).boolValue;
-    }
-
-    /**
-     * TODO: doc
-     */
-    public void setWifiEnabled(boolean enable) {
-        mLastEnableUid.set(Binder.getCallingUid());
-        if (enable) {
-            /* Argument is the state that is entered prior to load */
-            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
-            sendMessage(CMD_START_SUPPLICANT);
-        } else {
-            sendMessage(CMD_STOP_SUPPLICANT);
-            /* Argument is the state that is entered upon success */
-            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
-        }
-    }
-
-    /**
-     * TODO: doc
-     */
-    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
-        mLastApEnableUid.set(Binder.getCallingUid());
-        if (enable) {
-            /* Argument is the state that is entered prior to load */
-            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
-            sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
-        } else {
-            sendMessage(CMD_STOP_AP);
-            /* Argument is the state that is entered upon success */
-            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
-        }
-    }
-
-    /**
-     * TODO: doc
-     */
-    public int getWifiState() {
-        return mWifiState.get();
-    }
-
-    /**
-     * TODO: doc
-     */
-    public String getWifiStateByName() {
-        switch (mWifiState.get()) {
-            case WIFI_STATE_DISABLING:
-                return "disabling";
-            case WIFI_STATE_DISABLED:
-                return "disabled";
-            case WIFI_STATE_ENABLING:
-                return "enabling";
-            case WIFI_STATE_ENABLED:
-                return "enabled";
-            case WIFI_STATE_UNKNOWN:
-                return "unknown state";
-            default:
-                return "[invalid state]";
-        }
-    }
-
-    /**
-     * TODO: doc
-     */
-    public int getWifiApState() {
-        return mWifiApState.get();
-    }
-
-    /**
-     * TODO: doc
-     */
-    public String getWifiApStateByName() {
-        switch (mWifiApState.get()) {
-            case WIFI_AP_STATE_DISABLING:
-                return "disabling";
-            case WIFI_AP_STATE_DISABLED:
-                return "disabled";
-            case WIFI_AP_STATE_ENABLING:
-                return "enabling";
-            case WIFI_AP_STATE_ENABLED:
-                return "enabled";
-            case WIFI_AP_STATE_FAILED:
-                return "failed";
-            default:
-                return "[invalid state]";
-        }
-    }
-
-    /**
-     * Get status information for the current connection, if any.
-     * @return a {@link WifiInfo} object containing information about the current connection
-     *
-     */
-    public WifiInfo requestConnectionInfo() {
-        return mWifiInfo;
-    }
-
-    public DhcpInfo getDhcpInfo() {
-        return mDhcpInfo;
-    }
-
-    /**
-     * TODO: doc
-     */
-    public void startWifi(boolean enable) {
-      if (enable) {
-          sendMessage(CMD_START_DRIVER);
-      } else {
-          sendMessage(CMD_STOP_DRIVER);
-      }
-    }
-
-    /**
-     * TODO: doc
-     */
-    public void disconnectAndStop() {
-        sendMessage(CMD_DISCONNECT);
-        sendMessage(CMD_STOP_DRIVER);
-    }
-
-    /**
-     * TODO: doc
-     */
-    public void setScanOnlyMode(boolean enable) {
-      if (enable) {
-          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
-      } else {
-          sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
-      }
-    }
-
-    /**
-     * TODO: doc
-     */
-    public void setScanType(boolean active) {
-      if (active) {
-          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0));
-      } else {
-          sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0));
-      }
-    }
-
-    /**
-     * TODO: doc
-     */
-    public List<ScanResult> getScanResultsList() {
-        return mScanResults;
-    }
-
-    /**
-     * Disconnect from Access Point
-     */
-    public boolean disconnectCommand() {
-        return sendSyncMessage(CMD_DISCONNECT).boolValue;
-    }
-
-    /**
-     * Initiate a reconnection to AP
-     */
-    public boolean reconnectCommand() {
-        return sendSyncMessage(CMD_RECONNECT).boolValue;
-    }
-
-    /**
-     * Initiate a re-association to AP
-     */
-    public boolean reassociateCommand() {
-        return sendSyncMessage(CMD_REASSOCIATE).boolValue;
-    }
-
-    /**
-     * Add a network synchronously
-     *
-     * @return network id of the new network
-     */
-    public int addOrUpdateNetwork(WifiConfiguration config) {
-        return sendSyncMessage(CMD_ADD_OR_UPDATE_NETWORK, config).intValue;
-    }
-
-    public List<WifiConfiguration> getConfiguredNetworks() {
-        return sendSyncMessage(CMD_GET_NETWORK_CONFIG).configList;
-    }
-
-    /**
-     * Delete a network
-     *
-     * @param networkId id of the network to be removed
-     */
-    public boolean removeNetwork(int networkId) {
-        return sendSyncMessage(obtainMessage(CMD_REMOVE_NETWORK, networkId, 0)).boolValue;
-    }
-
-    private class EnableNetParams {
-        private int netId;
-        private boolean disableOthers;
-        EnableNetParams(int n, boolean b) {
-            netId = n;
-            disableOthers = b;
-        }
-    }
-    /**
-     * Enable a network
-     *
-     * @param netId network id of the network
-     * @param disableOthers true, if all other networks have to be disabled
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     */
-    public boolean enableNetwork(int netId, boolean disableOthers) {
-        return sendSyncMessage(CMD_ENABLE_NETWORK,
-                new EnableNetParams(netId, disableOthers)).boolValue;
-    }
-
-    /**
-     * Disable a network
-     *
-     * @param netId network id of the network
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     */
-    public boolean disableNetwork(int netId) {
-        return sendSyncMessage(obtainMessage(CMD_DISABLE_NETWORK, netId, 0)).boolValue;
-    }
-
-    /**
-     * Blacklist a BSSID. This will avoid the AP if there are
-     * alternate APs to connect
-     *
-     * @param bssid BSSID of the network
-     */
-    public void addToBlacklist(String bssid) {
-        sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
-    }
-
-    /**
-     * Clear the blacklist list
-     *
-     */
-    public void clearBlacklist() {
-        sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
-    }
-
-    /**
-     * Get detailed status of the connection
-     *
-     * @return Example status result
-     *  bssid=aa:bb:cc:dd:ee:ff
-     *  ssid=TestNet
-     *  id=3
-     *  pairwise_cipher=NONE
-     *  group_cipher=NONE
-     *  key_mgmt=NONE
-     *  wpa_state=COMPLETED
-     *  ip_address=X.X.X.X
-     */
-    public String status() {
-        return sendSyncMessage(CMD_CONNECTION_STATUS).stringValue;
-    }
-
-    public void enableRssiPolling(boolean enabled) {
-       sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
-    }
-    /**
-     * Get RSSI to currently connected network
-     *
-     * @return RSSI value, -1 on failure
-     */
-    public int getRssi() {
-        return sendSyncMessage(CMD_GET_RSSI).intValue;
-    }
-
-    /**
-     * Get approx RSSI to currently connected network
-     *
-     * @return RSSI value, -1 on failure
-     */
-    public int getRssiApprox() {
-        return sendSyncMessage(CMD_GET_RSSI_APPROX).intValue;
-    }
-
-    /**
-     * Get link speed to currently connected network
-     *
-     * @return link speed, -1 on failure
-     */
-    public int getLinkSpeed() {
-        return sendSyncMessage(CMD_GET_LINK_SPEED).intValue;
-    }
-
-    /**
-     * Get MAC address of radio
-     *
-     * @return MAC address, null on failure
-     */
-    public String getMacAddress() {
-        return sendSyncMessage(CMD_GET_MAC_ADDR).stringValue;
-    }
-
-    /**
-     * Start packet filtering
-     */
-    public void startPacketFiltering() {
-        sendMessage(CMD_START_PACKET_FILTERING);
-    }
-
-    /**
-     * Stop packet filtering
-     */
-    public void stopPacketFiltering() {
-        sendMessage(CMD_STOP_PACKET_FILTERING);
-    }
-
-    /**
-     * Set power mode
-     * @param mode
-     *     DRIVER_POWER_MODE_AUTO
-     *     DRIVER_POWER_MODE_ACTIVE
-     */
-    public void setPowerMode(int mode) {
-        sendMessage(obtainMessage(CMD_SET_POWER_MODE, mode, 0));
-    }
-
-    /**
-     * Set the number of allowed radio frequency channels from the system
-     * setting value, if any.
-     */
-    public void setNumAllowedChannels() {
-        try {
-            setNumAllowedChannels(
-                    Settings.Secure.getInt(mContext.getContentResolver(),
-                    Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
-        } catch (Settings.SettingNotFoundException e) {
-            if (mNumAllowedChannels != 0) {
-                setNumAllowedChannels(mNumAllowedChannels);
-            }
-            // otherwise, use the driver default
-        }
-    }
-
-    /**
-     * Set the number of radio frequency channels that are allowed to be used
-     * in the current regulatory domain.
-     * @param numChannels the number of allowed channels. Must be greater than 0
-     * and less than or equal to 16.
-     */
-    public void setNumAllowedChannels(int numChannels) {
-        sendMessage(obtainMessage(CMD_SET_NUM_ALLOWED_CHANNELS, numChannels, 0));
-    }
-
-    /**
-     * Get number of allowed channels
-     *
-     * @return channel count, -1 on failure
-     *
-     * TODO: this is not a public API and needs to be removed in favor
-     * of asynchronous reporting. unused for now.
-     */
-    public int getNumAllowedChannels() {
-        return -1;
-    }
-
-    /**
-     * Set bluetooth coex mode:
-     *
-     * @param mode
-     *  BLUETOOTH_COEXISTENCE_MODE_ENABLED
-     *  BLUETOOTH_COEXISTENCE_MODE_DISABLED
-     *  BLUETOOTH_COEXISTENCE_MODE_SENSE
-     */
-    public void setBluetoothCoexistenceMode(int mode) {
-        sendMessage(obtainMessage(CMD_SET_BLUETOOTH_COEXISTENCE, mode, 0));
-    }
-
-    /**
-     * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
-     * some of the low-level scan parameters used by the driver are changed to
-     * reduce interference with A2DP streaming.
-     *
-     * @param isBluetoothPlaying whether to enable or disable this mode
-     */
-    public void setBluetoothScanMode(boolean isBluetoothPlaying) {
-        sendMessage(obtainMessage(CMD_SET_BLUETOOTH_SCAN_MODE, isBluetoothPlaying ? 1 : 0, 0));
-    }
-
-    /**
-     * Save configuration on supplicant
-     *
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     *
-     * TODO: deprecate this
-     */
-    public boolean saveConfig() {
-        return sendSyncMessage(CMD_SAVE_CONFIG).boolValue;
-    }
-
-    /**
-     * TODO: doc
-     */
-    public void requestCmWakeLock() {
-        sendMessage(CMD_REQUEST_CM_WAKELOCK);
-    }
-
-    /*********************************************************
-     * Internal private functions
-     ********************************************************/
-
-    class SyncReturn {
-        boolean boolValue;
-        int intValue;
-        String stringValue;
-        Object objValue;
-        List<WifiConfiguration> configList;
-    }
-
-    class SyncParams {
-        Object mParameter;
-        SyncReturn mSyncReturn;
-        SyncParams() {
-            mSyncReturn = new SyncReturn();
-        }
-        SyncParams(Object p) {
-            mParameter = p;
-            mSyncReturn = new SyncReturn();
-        }
-    }
-
-    /**
-     * message.arg2 is reserved to indicate synchronized
-     * message.obj is used to store SyncParams
-     */
-    private SyncReturn syncedSend(Message msg) {
-        SyncParams syncParams = (SyncParams) msg.obj;
-        msg.arg2 = SYNCHRONOUS_CALL;
-        synchronized(syncParams) {
-            if (DBG) Log.d(TAG, "syncedSend " + msg);
-            sendMessage(msg);
-            try {
-                syncParams.wait();
-            } catch (InterruptedException e) {
-                Log.e(TAG, "sendSyncMessage: unexpected interruption of wait()");
-                return null;
-            }
-        }
-        return syncParams.mSyncReturn;
-    }
-
-    private SyncReturn sendSyncMessage(Message msg) {
-        SyncParams syncParams = new SyncParams();
-        msg.obj = syncParams;
-        return syncedSend(msg);
-    }
-
-    private SyncReturn sendSyncMessage(int what, Object param) {
-        SyncParams syncParams = new SyncParams(param);
-        Message msg = obtainMessage(what, syncParams);
-        return syncedSend(msg);
-    }
-
-
-    private SyncReturn sendSyncMessage(int what) {
-        return sendSyncMessage(obtainMessage(what));
-    }
-
-    private void notifyOnMsgObject(Message msg) {
-        SyncParams syncParams = (SyncParams) msg.obj;
-        if (syncParams != null) {
-            synchronized(syncParams) {
-                if (DBG) Log.d(TAG, "notifyOnMsgObject " + msg);
-                syncParams.notify();
-            }
-        }
-        else {
-            Log.e(TAG, "Error! syncParams in notifyOnMsgObject is null");
-        }
-    }
-
-    private void setWifiState(int wifiState) {
-        final int previousWifiState = mWifiState.get();
-
-        try {
-            if (wifiState == WIFI_STATE_ENABLED) {
-                mBatteryStats.noteWifiOn(mLastEnableUid.get());
-            } else if (wifiState == WIFI_STATE_DISABLED) {
-                mBatteryStats.noteWifiOff(mLastEnableUid.get());
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to note battery stats in wifi");
-        }
-
-        mWifiState.set(wifiState);
-
-        if (DBG) Log.d(TAG, "setWifiState: " + getWifiStateByName());
-
-        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
-        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
-        mContext.sendStickyBroadcast(intent);
-    }
-
-    private void setWifiApState(int wifiApState) {
-        final int previousWifiApState = mWifiApState.get();
-
-        try {
-            if (wifiApState == WIFI_AP_STATE_ENABLED) {
-                mBatteryStats.noteWifiOn(mLastApEnableUid.get());
-            } else if (wifiApState == WIFI_AP_STATE_DISABLED) {
-                mBatteryStats.noteWifiOff(mLastApEnableUid.get());
-            }
-        } catch (RemoteException e) {
-            Log.d(TAG, "Failed to note battery stats in wifi");
-        }
-
-        // Update state
-        mWifiApState.set(wifiApState);
-
-        if (DBG) Log.d(TAG, "setWifiApState: " + getWifiApStateByName());
-
-        // Broadcast
-        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
-        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
-        mContext.sendStickyBroadcast(intent);
-    }
-
-    /**
-     * Parse the scan result line passed to us by wpa_supplicant (helper).
-     * @param line the line to parse
-     * @return the {@link ScanResult} object
-     */
-    private ScanResult parseScanResult(String line) {
-        ScanResult scanResult = null;
-        if (line != null) {
-            /*
-             * Cache implementation (LinkedHashMap) is not synchronized, thus,
-             * must synchronized here!
-             */
-            synchronized (mScanResultCache) {
-                String[] result = scanResultPattern.split(line);
-                if (3 <= result.length && result.length <= 5) {
-                    String bssid = result[0];
-                    // bssid | frequency | level | flags | ssid
-                    int frequency;
-                    int level;
-                    try {
-                        frequency = Integer.parseInt(result[1]);
-                        level = Integer.parseInt(result[2]);
-                        /* some implementations avoid negative values by adding 256
-                         * so we need to adjust for that here.
-                         */
-                        if (level > 0) level -= 256;
-                    } catch (NumberFormatException e) {
-                        frequency = 0;
-                        level = 0;
-                    }
-
-                    /*
-                     * The formatting of the results returned by
-                     * wpa_supplicant is intended to make the fields
-                     * line up nicely when printed,
-                     * not to make them easy to parse. So we have to
-                     * apply some heuristics to figure out which field
-                     * is the SSID and which field is the flags.
-                     */
-                    String ssid;
-                    String flags;
-                    if (result.length == 4) {
-                        if (result[3].charAt(0) == '[') {
-                            flags = result[3];
-                            ssid = "";
-                        } else {
-                            flags = "";
-                            ssid = result[3];
-                        }
-                    } else if (result.length == 5) {
-                        flags = result[3];
-                        ssid = result[4];
-                    } else {
-                        // Here, we must have 3 fields: no flags and ssid
-                        // set
-                        flags = "";
-                        ssid = "";
-                    }
-
-                    // bssid + ssid is the hash key
-                    String key = bssid + ssid;
-                    scanResult = mScanResultCache.get(key);
-                    if (scanResult != null) {
-                        scanResult.level = level;
-                        scanResult.SSID = ssid;
-                        scanResult.capabilities = flags;
-                        scanResult.frequency = frequency;
-                    } else {
-                        // Do not add scan results that have no SSID set
-                        if (0 < ssid.trim().length()) {
-                            scanResult =
-                                new ScanResult(
-                                    ssid, bssid, flags, level, frequency);
-                            mScanResultCache.put(key, scanResult);
-                        }
-                    }
-                } else {
-                    Log.w(TAG, "Misformatted scan result text with " +
-                          result.length + " fields: " + line);
-                }
-            }
-        }
-
-        return scanResult;
-    }
-
-    /**
-     * scanResults input format
-     * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
-     * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
-     */
-    private void setScanResults(String scanResults) {
-        if (scanResults == null) {
-            return;
-        }
-
-        List<ScanResult> scanList = new ArrayList<ScanResult>();
-
-        int lineCount = 0;
-
-        int scanResultsLen = scanResults.length();
-        // Parse the result string, keeping in mind that the last line does
-        // not end with a newline.
-        for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
-            if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
-                ++lineCount;
-
-                if (lineCount == 1) {
-                    lineBeg = lineEnd + 1;
-                    continue;
-                }
-                if (lineEnd > lineBeg) {
-                    String line = scanResults.substring(lineBeg, lineEnd);
-                    ScanResult scanResult = parseScanResult(line);
-                    if (scanResult != null) {
-                        scanList.add(scanResult);
-                    } else {
-                        Log.w(TAG, "misformatted scan result for: " + line);
-                    }
-                }
-                lineBeg = lineEnd + 1;
-            }
-        }
-
-        mScanResults = scanList;
-    }
-
-    private void checkAndSetNotification() {
-        // If we shouldn't place a notification on available networks, then
-        // don't bother doing any of the following
-        if (!mNotificationEnabled) return;
-
-        State state = mNetworkInfo.getState();
-        if ((state == NetworkInfo.State.DISCONNECTED)
-                || (state == NetworkInfo.State.UNKNOWN)) {
-            // Look for an open network
-            List<ScanResult> scanResults = mScanResults;
-            if (scanResults != null) {
-                int numOpenNetworks = 0;
-                for (int i = scanResults.size() - 1; i >= 0; i--) {
-                    ScanResult scanResult = scanResults.get(i);
-
-                    if (TextUtils.isEmpty(scanResult.capabilities)) {
-                        numOpenNetworks++;
-                    }
-                }
-
-                if (numOpenNetworks > 0) {
-                    if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
-                        /*
-                         * We've scanned continuously at least
-                         * NUM_SCANS_BEFORE_NOTIFICATION times. The user
-                         * probably does not have a remembered network in range,
-                         * since otherwise supplicant would have tried to
-                         * associate and thus resetting this counter.
-                         */
-                        setNotificationVisible(true, numOpenNetworks, false, 0);
-                    }
-                    return;
-                }
-            }
-        }
-
-        // No open networks in range, remove the notification
-        setNotificationVisible(false, 0, false, 0);
-    }
-
-    /**
-     * Display or don't display a notification that there are open Wi-Fi networks.
-     * @param visible {@code true} if notification should be visible, {@code false} otherwise
-     * @param numNetworks the number networks seen
-     * @param force {@code true} to force notification to be shown/not-shown,
-     * even if it is already shown/not-shown.
-     * @param delay time in milliseconds after which the notification should be made
-     * visible or invisible.
-     */
-    private void setNotificationVisible(boolean visible, int numNetworks, boolean force,
-            int delay) {
-
-        // Since we use auto cancel on the notification, when the
-        // mNetworksAvailableNotificationShown is true, the notification may
-        // have actually been canceled.  However, when it is false we know
-        // for sure that it is not being shown (it will not be shown any other
-        // place than here)
-
-        // If it should be hidden and it is already hidden, then noop
-        if (!visible && !mNotificationShown && !force) {
-            return;
-        }
-
-        Message message;
-        if (visible) {
-
-            // Not enough time has passed to show the notification again
-            if (System.currentTimeMillis() < mNotificationRepeatTime) {
-                return;
-            }
-
-            if (mNotification == null) {
-                // Cache the Notification mainly so we can remove the
-                // EVENT_NOTIFICATION_CHANGED message with this Notification from
-                // the queue later
-                mNotification = new Notification();
-                mNotification.when = 0;
-                mNotification.icon = ICON_NETWORKS_AVAILABLE;
-                mNotification.flags = Notification.FLAG_AUTO_CANCEL;
-                mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
-                        new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
-            }
-
-            CharSequence title = mContext.getResources().getQuantityText(
-                    com.android.internal.R.plurals.wifi_available, numNetworks);
-            CharSequence details = mContext.getResources().getQuantityText(
-                    com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
-            mNotification.tickerText = title;
-            mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
-
-            mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
-
-            message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 1,
-                    ICON_NETWORKS_AVAILABLE, mNotification);
-
-        } else {
-
-            // Remove any pending messages to show the notification
-            mCsHandler.removeMessages(EVENT_NOTIFICATION_CHANGED, mNotification);
-
-            message = mCsHandler.obtainMessage(EVENT_NOTIFICATION_CHANGED, 0,
-                    ICON_NETWORKS_AVAILABLE);
-        }
-
-        mCsHandler.sendMessageDelayed(message, delay);
-
-        mNotificationShown = visible;
-    }
-
-    private void configureNetworkProperties() {
-        try {
-            mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName));
-        } catch (SocketException e) {
-            Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName +
-                    ". e=" + e);
-            return;
-        } catch (NullPointerException e) {
-            Log.e(TAG, "NPE creating NetworkInterface. e=" + e);
-            return;
-        }
-        // TODO - fix this for v6
-        try {
-            mNetworkProperties.addAddress(InetAddress.getByAddress(
-                    NetworkUtils.v4IntToArray(mDhcpInfo.ipAddress)));
-        } catch (UnknownHostException e) {
-            Log.e(TAG, "Exception setting IpAddress using " + mDhcpInfo + ", e=" + e);
-        }
-
-        try {
-            mNetworkProperties.setGateway(InetAddress.getByAddress(NetworkUtils.v4IntToArray(
-                    mDhcpInfo.gateway)));
-        } catch (UnknownHostException e) {
-            Log.e(TAG, "Exception setting Gateway using " + mDhcpInfo + ", e=" + e);
-        }
-
-        try {
-            mNetworkProperties.addDns(InetAddress.getByAddress(
-                    NetworkUtils.v4IntToArray(mDhcpInfo.dns1)));
-        } catch (UnknownHostException e) {
-            Log.e(TAG, "Exception setting Dns1 using " + mDhcpInfo + ", e=" + e);
-        }
-        try {
-            mNetworkProperties.addDns(InetAddress.getByAddress(
-                    NetworkUtils.v4IntToArray(mDhcpInfo.dns2)));
-
-        } catch (UnknownHostException e) {
-            Log.e(TAG, "Exception setting Dns2 using " + mDhcpInfo + ", e=" + e);
-        }
-        // TODO - add proxy info
-    }
-
-
-    private void checkUseStaticIp() {
-        mUseStaticIp = false;
-        final ContentResolver cr = mContext.getContentResolver();
-        try {
-            if (Settings.System.getInt(cr, Settings.System.WIFI_USE_STATIC_IP) == 0) {
-                return;
-            }
-        } catch (Settings.SettingNotFoundException e) {
-            return;
-        }
-
-        try {
-            String addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_IP);
-            if (addr != null) {
-                mDhcpInfo.ipAddress = stringToIpAddr(addr);
-            } else {
-                return;
-            }
-            addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_GATEWAY);
-            if (addr != null) {
-                mDhcpInfo.gateway = stringToIpAddr(addr);
-            } else {
-                return;
-            }
-            addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_NETMASK);
-            if (addr != null) {
-                mDhcpInfo.netmask = stringToIpAddr(addr);
-            } else {
-                return;
-            }
-            addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS1);
-            if (addr != null) {
-                mDhcpInfo.dns1 = stringToIpAddr(addr);
-            } else {
-                return;
-            }
-            addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS2);
-            if (addr != null) {
-                mDhcpInfo.dns2 = stringToIpAddr(addr);
-            } else {
-                mDhcpInfo.dns2 = 0;
-            }
-        } catch (UnknownHostException e) {
-            return;
-        }
-        mUseStaticIp = true;
-    }
-
-    private static int stringToIpAddr(String addrString) throws UnknownHostException {
-        try {
-            String[] parts = addrString.split("\\.");
-            if (parts.length != 4) {
-                throw new UnknownHostException(addrString);
-            }
-
-            int a = Integer.parseInt(parts[0])      ;
-            int b = Integer.parseInt(parts[1]) <<  8;
-            int c = Integer.parseInt(parts[2]) << 16;
-            int d = Integer.parseInt(parts[3]) << 24;
-
-            return a | b | c | d;
-        } catch (NumberFormatException ex) {
-            throw new UnknownHostException(addrString);
-        }
-    }
-
-    private int getMaxDhcpRetries() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
-                                      Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
-                                      DEFAULT_MAX_DHCP_RETRIES);
-    }
-
-    private class SettingsObserver extends ContentObserver {
-        public SettingsObserver(Handler handler) {
-            super(handler);
-            ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(Settings.System.getUriFor(
-                Settings.System.WIFI_USE_STATIC_IP), false, this);
-            cr.registerContentObserver(Settings.System.getUriFor(
-                Settings.System.WIFI_STATIC_IP), false, this);
-            cr.registerContentObserver(Settings.System.getUriFor(
-                Settings.System.WIFI_STATIC_GATEWAY), false, this);
-            cr.registerContentObserver(Settings.System.getUriFor(
-                Settings.System.WIFI_STATIC_NETMASK), false, this);
-            cr.registerContentObserver(Settings.System.getUriFor(
-                Settings.System.WIFI_STATIC_DNS1), false, this);
-            cr.registerContentObserver(Settings.System.getUriFor(
-                Settings.System.WIFI_STATIC_DNS2), false, this);
-        }
-
+    private class WifiStateReceiver extends BroadcastReceiver {
         @Override
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-
-            boolean wasStaticIp = mUseStaticIp;
-            int oIp, oGw, oMsk, oDns1, oDns2;
-            oIp = oGw = oMsk = oDns1 = oDns2 = 0;
-            if (wasStaticIp) {
-                oIp = mDhcpInfo.ipAddress;
-                oGw = mDhcpInfo.gateway;
-                oMsk = mDhcpInfo.netmask;
-                oDns1 = mDhcpInfo.dns1;
-                oDns2 = mDhcpInfo.dns2;
-            }
-            checkUseStaticIp();
-
-            if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) {
-                return;
-            }
-
-            boolean changed =
-                (wasStaticIp != mUseStaticIp) ||
-                    (wasStaticIp && (
-                        oIp   != mDhcpInfo.ipAddress ||
-                        oGw   != mDhcpInfo.gateway ||
-                        oMsk  != mDhcpInfo.netmask ||
-                        oDns1 != mDhcpInfo.dns1 ||
-                        oDns2 != mDhcpInfo.dns2));
-
-            if (changed) {
-                sendMessage(CMD_RECONFIGURE_IP);
-                if (mUseStaticIp) {
-                    mCsHandler.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED);
-                }
+        public void onReceive(Context context, Intent intent) {
+           if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+                        WifiManager.EXTRA_NETWORK_INFO);
+                mNetworkProperties = (NetworkProperties) intent.getParcelableExtra(
+                        WifiManager.EXTRA_NETWORK_PROPERTIES);
+                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+                msg.sendToTarget();
+            } else if (intent.getAction().equals(WifiManager.CONFIG_CHANGED_ACTION)) {
+                mNetworkProperties = (NetworkProperties) intent.getParcelableExtra(
+                        WifiManager.EXTRA_NETWORK_PROPERTIES);
+                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
+                msg.sendToTarget();
             }
         }
     }
 
-
-    /**
-     * Clears variables related to tracking whether a notification has been
-     * shown recently.
-     * <p>
-     * After calling this method, the timer that prevents notifications from
-     * being shown too often will be cleared.
-     */
-    private void resetNotificationTimer() {
-        mNotificationRepeatTime = 0;
-        mNumScansSinceNetworkStateChange = 0;
-    }
-
-
-    /**
-     * Whether to disable coexistence mode while obtaining IP address. This
-     * logic will return true only if the current bluetooth
-     * headset/handsfree state is disconnected. This means if it is in an
-     * error state, we will NOT disable coexistence mode to err on the side
-     * of safety.
-     *
-     * @return Whether to disable coexistence mode.
-     */
-    private boolean shouldDisableCoexistenceMode() {
-        int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset());
-        return state == BluetoothHeadset.STATE_DISCONNECTED;
-    }
-
-    private void checkIsBluetoothPlaying() {
-        boolean isBluetoothPlaying = false;
-        Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks();
-
-        for (BluetoothDevice device : connected) {
-            if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) {
-                isBluetoothPlaying = true;
-                break;
-            }
-        }
-        setBluetoothScanMode(isBluetoothPlaying);
-    }
-
-    private void sendScanResultsAvailableBroadcast() {
-        if (!ActivityManagerNative.isSystemReady()) return;
-
-        mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
-    }
-
-    private void sendRssiChangeBroadcast(final int newRssi) {
-        if (!ActivityManagerNative.isSystemReady()) return;
-
-        Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
-        intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
-        mContext.sendBroadcast(intent);
-    }
-
-    private void sendNetworkStateChangeBroadcast(String bssid) {
-        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
-                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
-        if (bssid != null)
-            intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
-        mContext.sendStickyBroadcast(intent);
-    }
-
-    private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) {
-        Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
-                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state);
-        if (failedAuth) {
-            intent.putExtra(
-                WifiManager.EXTRA_SUPPLICANT_ERROR,
-                WifiManager.ERROR_AUTHENTICATING);
-        }
-        mContext.sendStickyBroadcast(intent);
-    }
-
-    private void sendSupplicantConnectionChangedBroadcast(boolean connected) {
-        if (!ActivityManagerNative.isSystemReady()) return;
-
-        Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
-        intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected);
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Record the detailed state of a network, and if it is a
-     * change from the previous state, send a notification to
-     * any listeners.
-     * @param state the new @{code DetailedState}
-     */
-    private void setDetailedState(NetworkInfo.DetailedState state) {
-        Log.d(TAG, "setDetailed state, old ="
-                + mNetworkInfo.getDetailedState() + " and new state=" + state);
-        if (state != mNetworkInfo.getDetailedState()) {
-            mNetworkInfo.setDetailedState(state, null, null);
-            Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
-            msg.sendToTarget();
-        }
-    }
-
-    private static String removeDoubleQuotes(String string) {
-      if (string.length() <= 2) return "";
-      return string.substring(1, string.length() - 1);
-    }
-
-    private static String convertToQuotedString(String string) {
-        return "\"" + string + "\"";
-    }
-
-    private static String makeString(BitSet set, String[] strings) {
-        StringBuffer buf = new StringBuffer();
-        int nextSetBit = -1;
-
-        /* Make sure all set bits are in [0, strings.length) to avoid
-         * going out of bounds on strings.  (Shouldn't happen, but...) */
-        set = set.get(0, strings.length);
-
-        while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
-            buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
-        }
-
-        // remove trailing space
-        if (set.cardinality() > 0) {
-            buf.setLength(buf.length() - 1);
-        }
-
-        return buf.toString();
-    }
-
-    private static int lookupString(String string, String[] strings) {
-        int size = strings.length;
-
-        string = string.replace('-', '_');
-
-        for (int i = 0; i < size; i++)
-            if (string.equals(strings[i]))
-                return i;
-
-        // if we ever get here, we should probably add the
-        // value to WifiConfiguration to reflect that it's
-        // supported by the WPA supplicant
-        Log.w(TAG, "Failed to look-up a string: " + string);
-
-        return -1;
-    }
-
-    private int addOrUpdateNetworkNative(WifiConfiguration config) {
-        /*
-         * If the supplied networkId is -1, we create a new empty
-         * network configuration. Otherwise, the networkId should
-         * refer to an existing configuration.
-         */
-        int netId = config.networkId;
-        boolean newNetwork = netId == -1;
-        // networkId of -1 means we want to create a new network
-
-        if (newNetwork) {
-            netId = WifiNative.addNetworkCommand();
-            if (netId < 0) {
-                Log.e(TAG, "Failed to add a network!");
-                return -1;
-          }
-        }
-
-        setVariables: {
-
-            if (config.SSID != null &&
-                    !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.ssidVarName,
-                        config.SSID)) {
-                Log.d(TAG, "failed to set SSID: "+config.SSID);
-                break setVariables;
-            }
-
-            if (config.BSSID != null &&
-                    !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.bssidVarName,
-                        config.BSSID)) {
-                Log.d(TAG, "failed to set BSSID: "+config.BSSID);
-                break setVariables;
-            }
-
-            String allowedKeyManagementString =
-                makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
-            if (config.allowedKeyManagement.cardinality() != 0 &&
-                    !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.KeyMgmt.varName,
-                        allowedKeyManagementString)) {
-                Log.d(TAG, "failed to set key_mgmt: "+
-                        allowedKeyManagementString);
-                break setVariables;
-            }
-
-            String allowedProtocolsString =
-                makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings);
-            if (config.allowedProtocols.cardinality() != 0 &&
-                    !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.Protocol.varName,
-                        allowedProtocolsString)) {
-                Log.d(TAG, "failed to set proto: "+
-                        allowedProtocolsString);
-                break setVariables;
-            }
-
-            String allowedAuthAlgorithmsString =
-                makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings);
-            if (config.allowedAuthAlgorithms.cardinality() != 0 &&
-                    !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.AuthAlgorithm.varName,
-                        allowedAuthAlgorithmsString)) {
-                Log.d(TAG, "failed to set auth_alg: "+
-                        allowedAuthAlgorithmsString);
-                break setVariables;
-            }
-
-            String allowedPairwiseCiphersString =
-                    makeString(config.allowedPairwiseCiphers,
-                    WifiConfiguration.PairwiseCipher.strings);
-            if (config.allowedPairwiseCiphers.cardinality() != 0 &&
-                    !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.PairwiseCipher.varName,
-                        allowedPairwiseCiphersString)) {
-                Log.d(TAG, "failed to set pairwise: "+
-                        allowedPairwiseCiphersString);
-                break setVariables;
-            }
-
-            String allowedGroupCiphersString =
-                makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings);
-            if (config.allowedGroupCiphers.cardinality() != 0 &&
-                    !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.GroupCipher.varName,
-                        allowedGroupCiphersString)) {
-                Log.d(TAG, "failed to set group: "+
-                        allowedGroupCiphersString);
-                break setVariables;
-            }
-
-            // Prevent client screw-up by passing in a WifiConfiguration we gave it
-            // by preventing "*" as a key.
-            if (config.preSharedKey != null && !config.preSharedKey.equals("*") &&
-                    !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.pskVarName,
-                        config.preSharedKey)) {
-                Log.d(TAG, "failed to set psk: "+config.preSharedKey);
-                break setVariables;
-            }
-
-            boolean hasSetKey = false;
-            if (config.wepKeys != null) {
-                for (int i = 0; i < config.wepKeys.length; i++) {
-                    // Prevent client screw-up by passing in a WifiConfiguration we gave it
-                    // by preventing "*" as a key.
-                    if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) {
-                        if (!WifiNative.setNetworkVariableCommand(
-                                    netId,
-                                    WifiConfiguration.wepKeyVarNames[i],
-                                    config.wepKeys[i])) {
-                            Log.d(TAG,
-                                    "failed to set wep_key"+i+": " +
-                                    config.wepKeys[i]);
-                            break setVariables;
-                        }
-                        hasSetKey = true;
-                    }
-                }
-            }
-
-            if (hasSetKey) {
-                if (!WifiNative.setNetworkVariableCommand(
-                            netId,
-                            WifiConfiguration.wepTxKeyIdxVarName,
-                            Integer.toString(config.wepTxKeyIndex))) {
-                    Log.d(TAG,
-                            "failed to set wep_tx_keyidx: "+
-                            config.wepTxKeyIndex);
-                    break setVariables;
-                }
-            }
-
-            if (!WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.priorityVarName,
-                        Integer.toString(config.priority))) {
-                Log.d(TAG, config.SSID + ": failed to set priority: "
-                        +config.priority);
-                break setVariables;
-            }
-
-            if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand(
-                        netId,
-                        WifiConfiguration.hiddenSSIDVarName,
-                        Integer.toString(config.hiddenSSID ? 1 : 0))) {
-                Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+
-                        config.hiddenSSID);
-                break setVariables;
-            }
-
-            for (WifiConfiguration.EnterpriseField field
-                    : config.enterpriseFields) {
-                String varName = field.varName();
-                String value = field.value();
-                if (value != null) {
-                    if (field != config.eap) {
-                        value = (value.length() == 0) ? "NULL" : convertToQuotedString(value);
-                    }
-                    if (!WifiNative.setNetworkVariableCommand(
-                                netId,
-                                varName,
-                                value)) {
-                        Log.d(TAG, config.SSID + ": failed to set " + varName +
-                                ": " + value);
-                        break setVariables;
-                    }
-                }
-            }
-            return netId;
-        }
-
-        if (newNetwork) {
-            WifiNative.removeNetworkCommand(netId);
-            Log.d(TAG,
-                    "Failed to set a network variable, removed network: "
-                    + netId);
-        }
-
-        return -1;
-    }
-
-    private List<WifiConfiguration> getConfiguredNetworksNative() {
-        String listStr = WifiNative.listNetworksCommand();
-
-        List<WifiConfiguration> networks =
-            new ArrayList<WifiConfiguration>();
-        if (listStr == null)
-            return networks;
-
-        String[] lines = listStr.split("\n");
-        // Skip the first line, which is a header
-        for (int i = 1; i < lines.length; i++) {
-            String[] result = lines[i].split("\t");
-            // network-id | ssid | bssid | flags
-            WifiConfiguration config = new WifiConfiguration();
-            try {
-                config.networkId = Integer.parseInt(result[0]);
-            } catch(NumberFormatException e) {
-                continue;
-            }
-            if (result.length > 3) {
-                if (result[3].indexOf("[CURRENT]") != -1)
-                    config.status = WifiConfiguration.Status.CURRENT;
-                else if (result[3].indexOf("[DISABLED]") != -1)
-                    config.status = WifiConfiguration.Status.DISABLED;
-                else
-                    config.status = WifiConfiguration.Status.ENABLED;
-            } else {
-                config.status = WifiConfiguration.Status.ENABLED;
-            }
-            readNetworkVariables(config);
-            networks.add(config);
-        }
-        return networks;
-    }
-
-    /**
-     * Read the variables from the supplicant daemon that are needed to
-     * fill in the WifiConfiguration object.
-     *
-     * @param config the {@link WifiConfiguration} object to be filled in.
-     */
-    private void readNetworkVariables(WifiConfiguration config) {
-
-        int netId = config.networkId;
-        if (netId < 0)
-            return;
-
-        /*
-         * TODO: maybe should have a native method that takes an array of
-         * variable names and returns an array of values. But we'd still
-         * be doing a round trip to the supplicant daemon for each variable.
-         */
-        String value;
-
-        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName);
-        if (!TextUtils.isEmpty(value)) {
-            config.SSID = removeDoubleQuotes(value);
-        } else {
-            config.SSID = null;
-        }
-
-        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName);
-        if (!TextUtils.isEmpty(value)) {
-            config.BSSID = value;
-        } else {
-            config.BSSID = null;
-        }
-
-        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName);
-        config.priority = -1;
-        if (!TextUtils.isEmpty(value)) {
-            try {
-                config.priority = Integer.parseInt(value);
-            } catch (NumberFormatException ignore) {
-            }
-        }
-
-        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName);
-        config.hiddenSSID = false;
-        if (!TextUtils.isEmpty(value)) {
-            try {
-                config.hiddenSSID = Integer.parseInt(value) != 0;
-            } catch (NumberFormatException ignore) {
-            }
-        }
-
-        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName);
-        config.wepTxKeyIndex = -1;
-        if (!TextUtils.isEmpty(value)) {
-            try {
-                config.wepTxKeyIndex = Integer.parseInt(value);
-            } catch (NumberFormatException ignore) {
-            }
-        }
-
-        for (int i = 0; i < 4; i++) {
-            value = WifiNative.getNetworkVariableCommand(netId,
-                    WifiConfiguration.wepKeyVarNames[i]);
-            if (!TextUtils.isEmpty(value)) {
-                config.wepKeys[i] = value;
-            } else {
-                config.wepKeys[i] = null;
-            }
-        }
-
-        value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName);
-        if (!TextUtils.isEmpty(value)) {
-            config.preSharedKey = value;
-        } else {
-            config.preSharedKey = null;
-        }
-
-        value = WifiNative.getNetworkVariableCommand(config.networkId,
-                WifiConfiguration.Protocol.varName);
-        if (!TextUtils.isEmpty(value)) {
-            String vals[] = value.split(" ");
-            for (String val : vals) {
-                int index =
-                    lookupString(val, WifiConfiguration.Protocol.strings);
-                if (0 <= index) {
-                    config.allowedProtocols.set(index);
-                }
-            }
-        }
-
-        value = WifiNative.getNetworkVariableCommand(config.networkId,
-                WifiConfiguration.KeyMgmt.varName);
-        if (!TextUtils.isEmpty(value)) {
-            String vals[] = value.split(" ");
-            for (String val : vals) {
-                int index =
-                    lookupString(val, WifiConfiguration.KeyMgmt.strings);
-                if (0 <= index) {
-                    config.allowedKeyManagement.set(index);
-                }
-            }
-        }
-
-        value = WifiNative.getNetworkVariableCommand(config.networkId,
-                WifiConfiguration.AuthAlgorithm.varName);
-        if (!TextUtils.isEmpty(value)) {
-            String vals[] = value.split(" ");
-            for (String val : vals) {
-                int index =
-                    lookupString(val, WifiConfiguration.AuthAlgorithm.strings);
-                if (0 <= index) {
-                    config.allowedAuthAlgorithms.set(index);
-                }
-            }
-        }
-
-        value = WifiNative.getNetworkVariableCommand(config.networkId,
-                WifiConfiguration.PairwiseCipher.varName);
-        if (!TextUtils.isEmpty(value)) {
-            String vals[] = value.split(" ");
-            for (String val : vals) {
-                int index =
-                    lookupString(val, WifiConfiguration.PairwiseCipher.strings);
-                if (0 <= index) {
-                    config.allowedPairwiseCiphers.set(index);
-                }
-            }
-        }
-
-        value = WifiNative.getNetworkVariableCommand(config.networkId,
-                WifiConfiguration.GroupCipher.varName);
-        if (!TextUtils.isEmpty(value)) {
-            String vals[] = value.split(" ");
-            for (String val : vals) {
-                int index =
-                    lookupString(val, WifiConfiguration.GroupCipher.strings);
-                if (0 <= index) {
-                    config.allowedGroupCiphers.set(index);
-                }
-            }
-        }
-
-        for (WifiConfiguration.EnterpriseField field :
-                config.enterpriseFields) {
-            value = WifiNative.getNetworkVariableCommand(netId,
-                    field.varName());
-            if (!TextUtils.isEmpty(value)) {
-                if (field != config.eap) value = removeDoubleQuotes(value);
-                field.setValue(value);
-            }
-        }
-
-    }
-
-    /**
-     * Poll for info not reported via events
-     * RSSI & Linkspeed
-     */
-    private void requestPolledInfo() {
-        int newRssi = WifiNative.getRssiCommand();
-        if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
-            /* some implementations avoid negative values by adding 256
-             * so we need to adjust for that here.
-             */
-            if (newRssi > 0) newRssi -= 256;
-            mWifiInfo.setRssi(newRssi);
-            /*
-             * Rather then sending the raw RSSI out every time it
-             * changes, we precalculate the signal level that would
-             * be displayed in the status bar, and only send the
-             * broadcast if that much more coarse-grained number
-             * changes. This cuts down greatly on the number of
-             * broadcasts, at the cost of not mWifiInforming others
-             * interested in RSSI of all the changes in signal
-             * level.
-             */
-            // TODO: The second arg to the call below needs to be a symbol somewhere, but
-            // it's actually the size of an array of icons that's private
-            // to StatusBar Policy.
-            int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
-            if (newSignalLevel != mLastSignalLevel) {
-                sendRssiChangeBroadcast(newRssi);
-            }
-            mLastSignalLevel = newSignalLevel;
-        } else {
-            mWifiInfo.setRssi(-200);
-        }
-        int newLinkSpeed = WifiNative.getLinkSpeedCommand();
-        if (newLinkSpeed != -1) {
-            mWifiInfo.setLinkSpeed(newLinkSpeed);
-        }
-    }
-
-    /**
-     * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
-     * using the interface, stopping DHCP & disabling interface
-     */
-    private void handleNetworkDisconnect() {
-        Log.d(TAG, "Reset connections and stopping DHCP");
-
-        /*
-         * Reset connections & stop DHCP
-         */
-        NetworkUtils.resetConnections(mInterfaceName);
-
-        if (!NetworkUtils.stopDhcp(mInterfaceName)) {
-            Log.e(TAG, "Could not stop DHCP");
-        }
-
-        /* Disable interface */
-        NetworkUtils.disableInterface(mInterfaceName);
-
-        /* send event to CM & network change broadcast */
-        setDetailedState(DetailedState.DISCONNECTED);
-        sendNetworkStateChangeBroadcast(mLastBssid);
-
-        /* Reset data structures */
-        mWifiInfo.setIpAddress(0);
-        mWifiInfo.setBSSID(null);
-        mWifiInfo.setSSID(null);
-        mWifiInfo.setNetworkId(-1);
-
-        /* Clear network properties */
-        mNetworkProperties.clear();
-
-        mLastBssid= null;
-        mLastNetworkId = -1;
-
-    }
-
-
-    /*********************************************************
-     * Notifications from WifiMonitor
-     ********************************************************/
-
-    /**
-     * A structure for supplying information about a supplicant state
-     * change in the STATE_CHANGE event message that comes from the
-     * WifiMonitor
-     * thread.
-     */
-    private static class StateChangeResult {
-        StateChangeResult(int networkId, String BSSID, Object state) {
-            this.state = state;
-            this.BSSID = BSSID;
-            this.networkId = networkId;
-        }
-        int networkId;
-        String BSSID;
-        Object state;
-    }
-
-    /**
-     * Send the tracker a notification that a user-entered password key
-     * may be incorrect (i.e., caused authentication to fail).
-     */
-    void notifyPasswordKeyMayBeIncorrect() {
-        sendMessage(PASSWORD_MAY_BE_INCORRECT_EVENT);
-    }
-
-    /**
-     * Send the tracker a notification that a connection to the supplicant
-     * daemon has been established.
-     */
-    void notifySupplicantConnection() {
-        sendMessage(SUP_CONNECTION_EVENT);
-    }
-
-    /**
-     * Send the tracker a notification that a connection to the supplicant
-     * daemon has been established.
-     */
-    void notifySupplicantLost() {
-        sendMessage(SUP_DISCONNECTION_EVENT);
-    }
-
-    /**
-     * Send the tracker a notification that the state of Wifi connectivity
-     * has changed.
-     * @param networkId the configured network on which the state change occurred
-     * @param newState the new network state
-     * @param BSSID when the new state is {@link DetailedState#CONNECTED
-     * NetworkInfo.DetailedState.CONNECTED},
-     * this is the MAC address of the access point. Otherwise, it
-     * is {@code null}.
-     */
-    void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) {
-        if (newState == NetworkInfo.DetailedState.CONNECTED) {
-            sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT,
-                    new StateChangeResult(networkId, BSSID, newState)));
-        } else {
-            sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT,
-                    new StateChangeResult(networkId, BSSID, newState)));
-        }
-    }
-
-    /**
-     * Send the tracker a notification that the state of the supplicant
-     * has changed.
-     * @param networkId the configured network on which the state change occurred
-     * @param newState the new {@code SupplicantState}
-     */
-    void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
-        sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
-                new StateChangeResult(networkId, BSSID, newState)));
-    }
-
-    /**
-     * Send the tracker a notification that a scan has completed, and results
-     * are available.
-     */
-    void notifyScanResultsAvailable() {
-        /**
-         * Switch scan mode over to passive.
-         * Turning off scan-only mode happens only in "Connect" mode
-         */
-        setScanType(false);
-        sendMessage(SCAN_RESULTS_EVENT);
-    }
-
-    void notifyDriverStarted() {
-        sendMessage(DRIVER_START_EVENT);
-    }
-
-    void notifyDriverStopped() {
-        sendMessage(DRIVER_STOP_EVENT);
-    }
-
-    void notifyDriverHung() {
-        setWifiEnabled(false);
-        setWifiEnabled(true);
-    }
-
-
-    /********************************************************
-     * HSM states
-     *******************************************************/
-
-    class DefaultState extends HierarchicalState {
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            SyncParams syncParams;
-            switch (message.what) {
-                    /* Synchronous call returns */
-                case CMD_PING_SUPPLICANT:
-                case CMD_START_SCAN:
-                case CMD_DISCONNECT:
-                case CMD_RECONNECT:
-                case CMD_REASSOCIATE:
-                case CMD_REMOVE_NETWORK:
-                case CMD_ENABLE_NETWORK:
-                case CMD_DISABLE_NETWORK:
-                case CMD_ADD_OR_UPDATE_NETWORK:
-                case CMD_GET_RSSI:
-                case CMD_GET_RSSI_APPROX:
-                case CMD_GET_LINK_SPEED:
-                case CMD_GET_MAC_ADDR:
-                case CMD_SAVE_CONFIG:
-                case CMD_CONNECTION_STATUS:
-                case CMD_GET_NETWORK_CONFIG:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = false;
-                        syncParams.mSyncReturn.intValue = -1;
-                        syncParams.mSyncReturn.stringValue = null;
-                        syncParams.mSyncReturn.configList = null;
-                        notifyOnMsgObject(message);
-                    }
-                    break;
-                case CM_CMD_TEARDOWN:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    mTeardownRequested.set(true);
-                    sendMessage(CMD_DISCONNECT);
-                    sendMessage(CMD_STOP_DRIVER);
-                    /* Mark wifi available when CM tears down */
-                    mNetworkInfo.setIsAvailable(true);
-                    break;
-                case CM_CMD_RECONNECT:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    mTeardownRequested.set(false);
-                    sendMessage(CMD_START_DRIVER);
-                    sendMessage(CMD_RECONNECT);
-                    break;
-                case CMD_ENABLE_RSSI_POLL:
-                    mEnableRssiPolling = (message.arg1 == 1);
-                    mSupplicantStateTracker.sendMessage(CMD_ENABLE_RSSI_POLL);
-                    break;
-                default:
-                    if (DBG) Log.w(TAG, "Unhandled " + message);
-                    break;
-            }
-            return HANDLED;
-        }
-    }
-
-    class InitialState extends HierarchicalState {
-        @Override
-        //TODO: could move logging into a common class
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            // [31-8] Reserved for future use
-            // [7 - 0] HSM state change
-            // 50021 wifi_state_changed (custom|1|5)
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
-            if (WifiNative.isDriverLoaded()) {
-                transitionTo(mDriverLoadedState);
-            }
-            else {
-                transitionTo(mDriverUnloadedState);
-            }
-        }
-    }
-
-    class DriverLoadingState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
-            final Message message = new Message();
-            message.copyFrom(getCurrentMessage());
-            new Thread(new Runnable() {
-                public void run() {
-                    sWakeLock.acquire();
-                    //enabling state
-                    switch(message.arg1) {
-                        case WIFI_STATE_ENABLING:
-                            setWifiState(WIFI_STATE_ENABLING);
-                            break;
-                        case WIFI_AP_STATE_ENABLING:
-                            setWifiApState(WIFI_AP_STATE_ENABLING);
-                            break;
-                    }
-
-                    if(WifiNative.loadDriver()) {
-                        Log.d(TAG, "Driver load successful");
-                        sendMessage(CMD_LOAD_DRIVER_SUCCESS);
-                    } else {
-                        Log.e(TAG, "Failed to load driver!");
-                        switch(message.arg1) {
-                            case WIFI_STATE_ENABLING:
-                                setWifiState(WIFI_STATE_UNKNOWN);
-                                break;
-                            case WIFI_AP_STATE_ENABLING:
-                                setWifiApState(WIFI_AP_STATE_FAILED);
-                                break;
-                        }
-                        sendMessage(CMD_LOAD_DRIVER_FAILURE);
-                    }
-                    sWakeLock.release();
-                }
-            }).start();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_LOAD_DRIVER_SUCCESS:
-                    transitionTo(mDriverLoadedState);
-                    break;
-                case CMD_LOAD_DRIVER_FAILURE:
-                    transitionTo(mDriverFailedState);
-                    break;
-                case CMD_LOAD_DRIVER:
-                case CMD_UNLOAD_DRIVER:
-                case CMD_START_SUPPLICANT:
-                case CMD_STOP_SUPPLICANT:
-                case CMD_START_AP:
-                case CMD_STOP_AP:
-                case CMD_START_DRIVER:
-                case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
-                case CMD_SET_NUM_ALLOWED_CHANNELS:
-                case CMD_START_PACKET_FILTERING:
-                case CMD_STOP_PACKET_FILTERING:
-                    deferMessage(message);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DriverLoadedState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch(message.what) {
-                case CMD_UNLOAD_DRIVER:
-                    transitionTo(mDriverUnloadingState);
-                    break;
-                case CMD_START_SUPPLICANT:
-                    if(WifiNative.startSupplicant()) {
-                        Log.d(TAG, "Supplicant start successful");
-                        mWifiMonitor.startMonitoring();
-                        setWifiState(WIFI_STATE_ENABLED);
-                        transitionTo(mWaitForSupState);
-                    } else {
-                        Log.e(TAG, "Failed to start supplicant!");
-                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
-                    }
-                    break;
-                case CMD_START_AP:
-                    try {
-                        nwService.startAccessPoint((WifiConfiguration) message.obj,
-                                    mInterfaceName,
-                                    SOFTAP_IFACE);
-                    } catch(Exception e) {
-                        Log.e(TAG, "Exception in startAccessPoint()");
-                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
-                        break;
-                    }
-                    Log.d(TAG, "Soft AP start successful");
-                    setWifiApState(WIFI_AP_STATE_ENABLED);
-                    transitionTo(mSoftApStartedState);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DriverUnloadingState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
-            final Message message = new Message();
-            message.copyFrom(getCurrentMessage());
-            new Thread(new Runnable() {
-                public void run() {
-                    if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-                    sWakeLock.acquire();
-                    if(WifiNative.unloadDriver()) {
-                        Log.d(TAG, "Driver unload successful");
-                        sendMessage(CMD_UNLOAD_DRIVER_SUCCESS);
-
-                        switch(message.arg1) {
-                            case WIFI_STATE_DISABLED:
-                            case WIFI_STATE_UNKNOWN:
-                                setWifiState(message.arg1);
-                                break;
-                            case WIFI_AP_STATE_DISABLED:
-                            case WIFI_AP_STATE_FAILED:
-                                setWifiApState(message.arg1);
-                                break;
-                        }
-                    } else {
-                        Log.e(TAG, "Failed to unload driver!");
-                        sendMessage(CMD_UNLOAD_DRIVER_FAILURE);
-
-                        switch(message.arg1) {
-                            case WIFI_STATE_DISABLED:
-                            case WIFI_STATE_UNKNOWN:
-                                setWifiState(WIFI_STATE_UNKNOWN);
-                                break;
-                            case WIFI_AP_STATE_DISABLED:
-                            case WIFI_AP_STATE_FAILED:
-                                setWifiApState(WIFI_AP_STATE_FAILED);
-                                break;
-                        }
-                    }
-                    sWakeLock.release();
-                }
-            }).start();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_UNLOAD_DRIVER_SUCCESS:
-                    transitionTo(mDriverUnloadedState);
-                    break;
-                case CMD_UNLOAD_DRIVER_FAILURE:
-                    transitionTo(mDriverFailedState);
-                    break;
-                case CMD_LOAD_DRIVER:
-                case CMD_UNLOAD_DRIVER:
-                case CMD_START_SUPPLICANT:
-                case CMD_STOP_SUPPLICANT:
-                case CMD_START_AP:
-                case CMD_STOP_AP:
-                case CMD_START_DRIVER:
-                case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
-                case CMD_SET_NUM_ALLOWED_CHANNELS:
-                case CMD_START_PACKET_FILTERING:
-                case CMD_STOP_PACKET_FILTERING:
-                    deferMessage(message);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DriverUnloadedState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_LOAD_DRIVER:
-                    transitionTo(mDriverLoadingState);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DriverFailedState extends HierarchicalState {
-        @Override
-        public void enter() {
-            Log.e(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            return NOT_HANDLED;
-        }
-    }
-
-
-    class WaitForSupState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch(message.what) {
-                case SUP_CONNECTION_EVENT:
-                    Log.d(TAG, "Supplicant connection established");
-                    mSupplicantStateTracker.resetSupplicantState();
-                    /* Initialize data structures */
-                    resetNotificationTimer();
-                    setTeardownRequested(false);
-                    mLastBssid = null;
-                    mLastNetworkId = -1;
-                    mLastSignalLevel = -1;
-
-                    mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
-
-                    //TODO: initialize and fix multicast filtering
-                    //mWM.initializeMulticastFiltering();
-
-                    if (mBluetoothA2dp == null) {
-                        mBluetoothA2dp = new BluetoothA2dp(mContext);
-                    }
-                    checkIsBluetoothPlaying();
-
-                    checkUseStaticIp();
-                    sendSupplicantConnectionChangedBroadcast(true);
-                    transitionTo(mDriverSupReadyState);
-                    break;
-                case CMD_STOP_SUPPLICANT:
-                    Log.d(TAG, "Stop supplicant received");
-                    WifiNative.stopSupplicant();
-                    transitionTo(mDriverLoadedState);
-                    break;
-                    /* Fail soft ap when waiting for supplicant start */
-                case CMD_START_AP:
-                    Log.d(TAG, "Failed to start soft AP with a running supplicant");
-                    setWifiApState(WIFI_AP_STATE_FAILED);
-                    break;
-                case CMD_START_DRIVER:
-                case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
-                case CMD_SET_NUM_ALLOWED_CHANNELS:
-                case CMD_START_PACKET_FILTERING:
-                case CMD_STOP_PACKET_FILTERING:
-                    deferMessage(message);
-                    break;
-                case CMD_STOP_AP:
-                case CMD_START_SUPPLICANT:
-                case CMD_UNLOAD_DRIVER:
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DriverSupReadyState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-            /* Initialize for connect mode operation at start */
-            mIsScanMode = false;
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            SyncParams syncParams;
-            switch(message.what) {
-                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
-                    Log.d(TAG, "Stop supplicant received");
-                    WifiNative.stopSupplicant();
-                    //$FALL-THROUGH$
-                case SUP_DISCONNECTION_EVENT:  /* Supplicant died */
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    //Remove any notifications on disconnection
-                    setNotificationVisible(false, 0, false, 0);
-                    WifiNative.closeSupplicantConnection();
-                    handleNetworkDisconnect();
-                    sendSupplicantConnectionChangedBroadcast(false);
-                    mSupplicantStateTracker.resetSupplicantState();
-                    transitionTo(mDriverLoadedState);
-
-                    /* When supplicant dies, unload driver and enter failed state */
-                    //TODO: consider bringing up supplicant again
-                    if (message.what == SUP_DISCONNECTION_EVENT) {
-                        Log.d(TAG, "Supplicant died, unloading driver");
-                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));
-                    }
-                    break;
-                case CMD_START_DRIVER:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    WifiNative.startDriverCommand();
-                    transitionTo(mDriverStartingState);
-                    break;
-                case SCAN_RESULTS_EVENT:
-                    setScanResults(WifiNative.scanResultsCommand());
-                    sendScanResultsAvailableBroadcast();
-                    checkAndSetNotification();
-                    break;
-                case CMD_PING_SUPPLICANT:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.boolValue = WifiNative.pingCommand();
-                    notifyOnMsgObject(message);
-                    break;
-                case CMD_ADD_OR_UPDATE_NETWORK:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    syncParams = (SyncParams) message.obj;
-                    WifiConfiguration config = (WifiConfiguration) syncParams.mParameter;
-                    syncParams.mSyncReturn.intValue = addOrUpdateNetworkNative(config);
-                    notifyOnMsgObject(message);
-                    break;
-                case CMD_REMOVE_NETWORK:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.removeNetworkCommand(
-                                message.arg1);
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.removeNetworkCommand(message.arg1);
-                    }
-                    break;
-                case CMD_ENABLE_NETWORK:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter;
-                        syncParams.mSyncReturn.boolValue = WifiNative.enableNetworkCommand(
-                                enableNetParams.netId, enableNetParams.disableOthers);
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.enableNetworkCommand(message.arg1, message.arg2 == 1);
-                    }
-                    break;
-                case CMD_DISABLE_NETWORK:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.disableNetworkCommand(
-                                message.arg1);
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.disableNetworkCommand(message.arg1);
-                    }
-                    break;
-                case CMD_BLACKLIST_NETWORK:
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    WifiNative.addToBlacklistCommand((String)message.obj);
-                    break;
-                case CMD_CLEAR_BLACKLIST:
-                    WifiNative.clearBlacklistCommand();
-                    break;
-                case CMD_GET_NETWORK_CONFIG:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.configList = getConfiguredNetworksNative();
-                    notifyOnMsgObject(message);
-                    break;
-                case CMD_SAVE_CONFIG:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.saveConfigCommand();
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.saveConfigCommand();
-                    }
-                    // Inform the backup manager about a data change
-                    IBackupManager ibm = IBackupManager.Stub.asInterface(
-                            ServiceManager.getService(Context.BACKUP_SERVICE));
-                    if (ibm != null) {
-                        try {
-                            ibm.dataChanged("com.android.providers.settings");
-                        } catch (Exception e) {
-                            // Try again later
-                        }
-                    }
-                    break;
-                case CMD_CONNECTION_STATUS:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.stringValue = WifiNative.statusCommand();
-                    notifyOnMsgObject(message);
-                    break;
-                case CMD_GET_MAC_ADDR:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.stringValue = WifiNative.getMacAddressCommand();
-                    notifyOnMsgObject(message);
-                    break;
-                    /* Cannot start soft AP while in client mode */
-                case CMD_START_AP:
-                    Log.d(TAG, "Failed to start soft AP with a running supplicant");
-                    EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    setWifiApState(WIFI_AP_STATE_FAILED);
-                    break;
-                case CMD_SET_SCAN_MODE:
-                    mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-    }
-
-    class DriverStartingState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch(message.what) {
-                case DRIVER_START_EVENT:
-                    transitionTo(mDriverStartedState);
-                    break;
-                    /* Queue driver commands & connection events */
-                case CMD_START_DRIVER:
-                case CMD_STOP_DRIVER:
-                case SUPPLICANT_STATE_CHANGE_EVENT:
-                case NETWORK_CONNECTION_EVENT:
-                case NETWORK_DISCONNECTION_EVENT:
-                case PASSWORD_MAY_BE_INCORRECT_EVENT:
-                case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
-                case CMD_SET_NUM_ALLOWED_CHANNELS:
-                case CMD_START_PACKET_FILTERING:
-                case CMD_STOP_PACKET_FILTERING:
-                    deferMessage(message);
-                    break;
-                    /* Queue the asynchronous version of these commands */
-                case CMD_START_SCAN:
-                case CMD_DISCONNECT:
-                case CMD_REASSOCIATE:
-                case CMD_RECONNECT:
-                    if (message.arg2 != SYNCHRONOUS_CALL) {
-                        deferMessage(message);
-                    }
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DriverStartedState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
-            try {
-                mBatteryStats.noteWifiRunning();
-            } catch (RemoteException ignore) {}
-
-            /* Initialize channel count */
-            setNumAllowedChannels();
-
-            if (mIsScanMode) {
-                WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
-                WifiNative.disconnectCommand();
-                transitionTo(mScanModeState);
-            } else {
-                WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
-                /* If supplicant has already connected, before we could finish establishing
-                 * the control channel connection, we miss all the supplicant events.
-                 * Disconnect and reconnect when driver has started to ensure we receive
-                 * all supplicant events.
-                 *
-                 * TODO: This is a bit unclean, ideally the supplicant should never
-                 * connect until told to do so by the framework
-                 */
-                WifiNative.disconnectCommand();
-                WifiNative.reconnectCommand();
-                transitionTo(mConnectModeState);
-            }
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            SyncParams syncParams;
-            switch(message.what) {
-                case CMD_SET_SCAN_TYPE:
-                    if (message.arg1 == SCAN_ACTIVE) {
-                        WifiNative.setScanModeCommand(true);
-                    } else {
-                        WifiNative.setScanModeCommand(false);
-                    }
-                    break;
-                case CMD_SET_POWER_MODE:
-                    WifiNative.setPowerModeCommand(message.arg1);
-                    break;
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                    WifiNative.setBluetoothCoexistenceModeCommand(message.arg1);
-                    break;
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
-                    WifiNative.setBluetoothCoexistenceScanModeCommand(message.arg1 == 1);
-                    break;
-                case CMD_SET_NUM_ALLOWED_CHANNELS:
-                    mNumAllowedChannels = message.arg1;
-                    WifiNative.setNumAllowedChannelsCommand(message.arg1);
-                    break;
-                case CMD_START_DRIVER:
-                    /* Ignore another driver start */
-                    break;
-                case CMD_STOP_DRIVER:
-                    WifiNative.stopDriverCommand();
-                    transitionTo(mDriverStoppingState);
-                    break;
-                case CMD_REQUEST_CM_WAKELOCK:
-                    if (mCm == null) {
-                        mCm = (ConnectivityManager)mContext.getSystemService(
-                                Context.CONNECTIVITY_SERVICE);
-                    }
-                    mCm.requestNetworkTransitionWakelock(TAG);
-                    break;
-                case CMD_START_PACKET_FILTERING:
-                    WifiNative.startPacketFiltering();
-                    break;
-                case CMD_STOP_PACKET_FILTERING:
-                    WifiNative.stopPacketFiltering();
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-        @Override
-        public void exit() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            try {
-                mBatteryStats.noteWifiStopped();
-            } catch (RemoteException ignore) { }
-        }
-    }
-
-    class DriverStoppingState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch(message.what) {
-                case DRIVER_STOP_EVENT:
-                    transitionTo(mDriverStoppedState);
-                    break;
-                    /* Queue driver commands */
-                case CMD_START_DRIVER:
-                case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
-                case CMD_SET_NUM_ALLOWED_CHANNELS:
-                case CMD_START_PACKET_FILTERING:
-                case CMD_STOP_PACKET_FILTERING:
-                    deferMessage(message);
-                    break;
-                    /* Queue the asynchronous version of these commands */
-                case CMD_START_SCAN:
-                case CMD_DISCONNECT:
-                case CMD_REASSOCIATE:
-                case CMD_RECONNECT:
-                    if (message.arg2 != SYNCHRONOUS_CALL) {
-                        deferMessage(message);
-                    }
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DriverStoppedState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
-            // Take down any open network notifications on driver stop
-            setNotificationVisible(false, 0, false, 0);
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            return NOT_HANDLED;
-        }
-    }
-
-    class ScanModeState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            SyncParams syncParams;
-            switch(message.what) {
-                case CMD_SET_SCAN_MODE:
-                    if (message.arg1 == SCAN_ONLY_MODE) {
-                        /* Ignore */
-                        return HANDLED;
-                    } else {
-                        WifiNative.setScanResultHandlingCommand(message.arg1);
-                        WifiNative.reconnectCommand();
-                        mIsScanMode = false;
-                        transitionTo(mDisconnectedState);
-                    }
-                    break;
-                case CMD_START_SCAN:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.scanCommand(
-                                message.arg1 == SCAN_ACTIVE);
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
-                    }
-                    break;
-                    /* Ignore */
-                case CMD_DISCONNECT:
-                case CMD_RECONNECT:
-                case CMD_REASSOCIATE:
-                case SUPPLICANT_STATE_CHANGE_EVENT:
-                case NETWORK_CONNECTION_EVENT:
-                case NETWORK_DISCONNECTION_EVENT:
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class ConnectModeState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            SyncParams syncParams;
-            StateChangeResult stateChangeResult;
-            switch(message.what) {
-                case PASSWORD_MAY_BE_INCORRECT_EVENT:
-                    mPasswordKeyMayBeIncorrect = true;
-                    break;
-                case SUPPLICANT_STATE_CHANGE_EVENT:
-                    stateChangeResult = (StateChangeResult) message.obj;
-                    mSupplicantStateTracker.handleEvent(stateChangeResult);
-                    break;
-                case CMD_START_SCAN:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = true;
-                        notifyOnMsgObject(message);
-                    }
-                    /* We need to set scan type in completed state */
-                    Message newMsg = obtainMessage();
-                    newMsg.copyFrom(message);
-                    mSupplicantStateTracker.sendMessage(newMsg);
-                    break;
-                    /* Do a redundant disconnect without transition */
-                case CMD_DISCONNECT:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.disconnectCommand();
-                    }
-                    break;
-                case CMD_RECONNECT:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.reconnectCommand();
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.reconnectCommand();
-                    }
-                    break;
-                case CMD_REASSOCIATE:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.reassociateCommand();
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.reassociateCommand();
-                    }
-                    break;
-                case SCAN_RESULTS_EVENT:
-                    /* Set the scan setting back to "connect" mode */
-                    WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
-                    /* Handle scan results */
-                    return NOT_HANDLED;
-                case NETWORK_CONNECTION_EVENT:
-                    Log.d(TAG,"Network connection established");
-                    stateChangeResult = (StateChangeResult) message.obj;
-
-                    /* Remove any notifications */
-                    setNotificationVisible(false, 0, false, 0);
-                    resetNotificationTimer();
-
-                    mWifiInfo.setBSSID(mLastBssid = stateChangeResult.BSSID);
-                    mWifiInfo.setNetworkId(stateChangeResult.networkId);
-                    mLastNetworkId = stateChangeResult.networkId;
-
-                    /* send event to CM & network change broadcast */
-                    setDetailedState(DetailedState.OBTAINING_IPADDR);
-                    sendNetworkStateChangeBroadcast(mLastBssid);
-
-                    transitionTo(mConnectingState);
-                    break;
-                case NETWORK_DISCONNECTION_EVENT:
-                    Log.d(TAG,"Network connection lost");
-                    handleNetworkDisconnect();
-                    transitionTo(mDisconnectedState);
-                    break;
-                case CMD_GET_RSSI:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.intValue = WifiNative.getRssiCommand();
-                    notifyOnMsgObject(message);
-                    break;
-                case CMD_GET_RSSI_APPROX:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.intValue = WifiNative.getRssiApproxCommand();
-                    notifyOnMsgObject(message);
-                    break;
-                case CMD_GET_LINK_SPEED:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.intValue = WifiNative.getLinkSpeedCommand();
-                    notifyOnMsgObject(message);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class ConnectingState extends HierarchicalState {
-        boolean modifiedBluetoothCoexistenceMode;
-        int powerMode;
-        Thread mDhcpThread;
-
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
-            if (!mUseStaticIp) {
-
-                mDhcpThread = null;
-                modifiedBluetoothCoexistenceMode = false;
-                powerMode = DRIVER_POWER_MODE_AUTO;
-
-                if (shouldDisableCoexistenceMode()) {
-                    /*
-                     * There are problems setting the Wi-Fi driver's power
-                     * mode to active when bluetooth coexistence mode is
-                     * enabled or sense.
-                     * <p>
-                     * We set Wi-Fi to active mode when
-                     * obtaining an IP address because we've found
-                     * compatibility issues with some routers with low power
-                     * mode.
-                     * <p>
-                     * In order for this active power mode to properly be set,
-                     * we disable coexistence mode until we're done with
-                     * obtaining an IP address.  One exception is if we
-                     * are currently connected to a headset, since disabling
-                     * coexistence would interrupt that connection.
-                     */
-                    modifiedBluetoothCoexistenceMode = true;
-
-                    // Disable the coexistence mode
-                    WifiNative.setBluetoothCoexistenceModeCommand(
-                            WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
-                }
-
-                powerMode =  WifiNative.getPowerModeCommand();
-                if (powerMode < 0) {
-                  // Handle the case where supplicant driver does not support
-                  // getPowerModeCommand.
-                    powerMode = DRIVER_POWER_MODE_AUTO;
-                }
-                if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
-                    WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);
-                }
-
-                Log.d(TAG, "DHCP request started");
-                mDhcpThread = new Thread(new Runnable() {
-                    public void run() {
-                        if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
-                            Log.d(TAG, "DHCP request succeeded");
-                            sendMessage(CMD_IP_CONFIG_SUCCESS);
-                        } else {
-                            Log.d(TAG, "DHCP request failed: " +
-                                    NetworkUtils.getDhcpError());
-                            sendMessage(CMD_IP_CONFIG_FAILURE);
-                        }
-                    }
-                });
-                mDhcpThread.start();
-            } else {
-                if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {
-                    Log.v(TAG, "Static IP configuration succeeded");
-                    sendMessage(CMD_IP_CONFIG_SUCCESS);
-                } else {
-                    Log.v(TAG, "Static IP configuration failed");
-                    sendMessage(CMD_IP_CONFIG_FAILURE);
-                }
-            }
-         }
-      @Override
-      public boolean processMessage(Message message) {
-          if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-
-          switch(message.what) {
-              case CMD_IP_CONFIG_SUCCESS:
-                  mReconnectCount = 0;
-                  mLastSignalLevel = -1; // force update of signal strength
-                  mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
-                  Log.d(TAG, "IP configuration: " + mDhcpInfo);
-                  configureNetworkProperties();
-                  setDetailedState(DetailedState.CONNECTED);
-                  sendNetworkStateChangeBroadcast(mLastBssid);
-                  transitionTo(mConnectedState);
-                  break;
-              case CMD_IP_CONFIG_FAILURE:
-                  mWifiInfo.setIpAddress(0);
-
-                  Log.e(TAG, "IP configuration failed");
-                  /**
-                   * If we've exceeded the maximum number of retries for DHCP
-                   * to a given network, disable the network
-                   */
-                  if (++mReconnectCount > getMaxDhcpRetries()) {
-                          Log.e(TAG, "Failed " +
-                                  mReconnectCount + " times, Disabling " + mLastNetworkId);
-                      WifiNative.disableNetworkCommand(mLastNetworkId);
-                  }
-
-                  /* DHCP times out after about 30 seconds, we do a
-                   * disconnect and an immediate reconnect to try again
-                   */
-                  WifiNative.disconnectCommand();
-                  WifiNative.reconnectCommand();
-                  transitionTo(mDisconnectingState);
-                  break;
-              case CMD_DISCONNECT:
-                  if (message.arg2 == SYNCHRONOUS_CALL) {
-                      SyncParams syncParams = (SyncParams) message.obj;
-                      syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
-                      notifyOnMsgObject(message);
-                  } else {
-                      /* asynchronous handling */
-                      WifiNative.disconnectCommand();
-                  }
-                  transitionTo(mDisconnectingState);
-                  break;
-                  /* Ignore */
-              case NETWORK_CONNECTION_EVENT:
-                  break;
-              case CMD_STOP_DRIVER:
-                  sendMessage(CMD_DISCONNECT);
-                  deferMessage(message);
-                  break;
-              case CMD_SET_SCAN_MODE:
-                  if (message.arg1 == SCAN_ONLY_MODE) {
-                      sendMessage(CMD_DISCONNECT);
-                      deferMessage(message);
-                  }
-                  break;
-              case CMD_RECONFIGURE_IP:
-                  deferMessage(message);
-                  break;
-              default:
-                return NOT_HANDLED;
-          }
-          EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-          return HANDLED;
-      }
-
-      @Override
-      public void exit() {
-          /* reset power state & bluetooth coexistence if on DHCP */
-          if (!mUseStaticIp) {
-              if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
-                  WifiNative.setPowerModeCommand(powerMode);
-              }
-
-              if (modifiedBluetoothCoexistenceMode) {
-                  // Set the coexistence mode back to its default value
-                  WifiNative.setBluetoothCoexistenceModeCommand(
-                          WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
-              }
-          }
-
-      }
-    }
-
-    class ConnectedState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_DISCONNECT:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        SyncParams syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.disconnectCommand();
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.disconnectCommand();
-                    }
-                    transitionTo(mDisconnectingState);
-                    break;
-                case CMD_RECONFIGURE_IP:
-                    Log.d(TAG,"Reconfiguring IP on connection");
-                    NetworkUtils.resetConnections(mInterfaceName);
-                    transitionTo(mConnectingState);
-                    break;
-                case CMD_STOP_DRIVER:
-                    sendMessage(CMD_DISCONNECT);
-                    deferMessage(message);
-                    break;
-                case CMD_SET_SCAN_MODE:
-                    if (message.arg1 == SCAN_ONLY_MODE) {
-                        sendMessage(CMD_DISCONNECT);
-                        deferMessage(message);
-                    }
-                    break;
-                    /* Ignore */
-                case NETWORK_CONNECTION_EVENT:
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DisconnectingState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */
-                    deferMessage(message);
-                    break;
-                case CMD_SET_SCAN_MODE:
-                    if (message.arg1 == SCAN_ONLY_MODE) {
-                        deferMessage(message);
-                    }
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class DisconnectedState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_SET_SCAN_MODE:
-                    if (message.arg1 == SCAN_ONLY_MODE) {
-                        WifiNative.setScanResultHandlingCommand(message.arg1);
-                        //Supplicant disconnect to prevent further connects
-                        WifiNative.disconnectCommand();
-                        mIsScanMode = true;
-                        transitionTo(mScanModeState);
-                    }
-                    break;
-                    /* Ignore network disconnect */
-                case NETWORK_DISCONNECTION_EVENT:
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class SoftApStartedState extends HierarchicalState {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch(message.what) {
-                case CMD_STOP_AP:
-                    Log.d(TAG,"Stopping Soft AP");
-                    setWifiApState(WIFI_AP_STATE_DISABLING);
-                    try {
-                        nwService.stopAccessPoint();
-                    } catch(Exception e) {
-                        Log.e(TAG, "Exception in stopAccessPoint()");
-                    }
-                    transitionTo(mDriverLoadedState);
-                    break;
-                case CMD_START_AP:
-                    Log.d(TAG,"SoftAP set on a running access point");
-                    try {
-                        nwService.setAccessPoint((WifiConfiguration) message.obj,
-                                    mInterfaceName,
-                                    SOFTAP_IFACE);
-                    } catch(Exception e) {
-                        Log.e(TAG, "Exception in nwService during soft AP set");
-                        try {
-                            nwService.stopAccessPoint();
-                        } catch (Exception ee) {
-                            Slog.e(TAG, "Could not stop AP, :" + ee);
-                        }
-                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
-                    }
-                    break;
-                /* Fail client mode operation when soft AP is enabled */
-                case CMD_START_SUPPLICANT:
-                    Log.e(TAG,"Cannot start supplicant with a running soft AP");
-                    setWifiState(WIFI_STATE_UNKNOWN);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-
-    class SupplicantStateTracker extends HierarchicalStateMachine {
-
-        private int mRssiPollToken = 0;
-
-        /**
-         * The max number of the WPA supplicant loop iterations before we
-         * decide that the loop should be terminated:
-         */
-        private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4;
-        private int mLoopDetectIndex = 0;
-        private int mLoopDetectCount = 0;
-
-        /**
-         *  Supplicant state change commands follow
-         *  the ordinal values defined in SupplicantState.java
-         */
-        private static final int DISCONNECTED           = 0;
-        private static final int INACTIVE               = 1;
-        private static final int SCANNING               = 2;
-        private static final int ASSOCIATING            = 3;
-        private static final int ASSOCIATED             = 4;
-        private static final int FOUR_WAY_HANDSHAKE     = 5;
-        private static final int GROUP_HANDSHAKE        = 6;
-        private static final int COMPLETED              = 7;
-        private static final int DORMANT                = 8;
-        private static final int UNINITIALIZED          = 9;
-        private static final int INVALID                = 10;
-
-        private HierarchicalState mUninitializedState;
-        private HierarchicalState mInitializedState;
-        private HierarchicalState mInactiveState;
-        private HierarchicalState mDisconnectState;
-        private HierarchicalState mScanState;
-        private HierarchicalState mConnectState;
-        private HierarchicalState mHandshakeState;
-        private HierarchicalState mCompletedState;
-        private HierarchicalState mDormantState;
-
-
-        public SupplicantStateTracker(Context context, Handler target) {
-            super(TAG, target.getLooper());
-
-            mUninitializedState = new UninitializedState();
-            mInitializedState = new InitializedState();
-            mInactiveState = new InactiveState();
-            mDisconnectState = new DisconnectedState();
-            mScanState = new ScanState();
-            mConnectState = new ConnectState();
-            mHandshakeState = new HandshakeState();
-            mCompletedState = new CompletedState();
-            mDormantState = new DormantState();
-
-
-            addState(mUninitializedState);
-            addState(mInitializedState);
-                addState(mInactiveState, mInitializedState);
-                addState(mDisconnectState, mInitializedState);
-                addState(mScanState, mInitializedState);
-                addState(mConnectState, mInitializedState);
-                    addState(mHandshakeState, mConnectState);
-                    addState(mCompletedState, mConnectState);
-                addState(mDormantState, mInitializedState);
-
-            setInitialState(mUninitializedState);
-
-            //start the state machine
-            start();
-        }
-
-        public void handleEvent(StateChangeResult stateChangeResult) {
-            SupplicantState newState = (SupplicantState) stateChangeResult.state;
-
-            // Supplicant state change
-            // [31-13] Reserved for future use
-            // [8 - 0] Supplicant state (as defined in SupplicantState.java)
-            // 50023 supplicant_state_changed (custom|1|5)
-            EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, newState.ordinal());
-
-            sendMessage(obtainMessage(newState.ordinal(), stateChangeResult));
-        }
-
-        public void resetSupplicantState() {
-            transitionTo(mUninitializedState);
-        }
-
-        private void resetLoopDetection() {
-            mLoopDetectCount = 0;
-            mLoopDetectIndex = 0;
-        }
-
-        private boolean handleTransition(Message msg) {
-            if (DBG) Log.d(TAG, getName() + msg.toString() + "\n");
-            switch (msg.what) {
-                case DISCONNECTED:
-                    transitionTo(mDisconnectState);
-                    break;
-                case SCANNING:
-                    transitionTo(mScanState);
-                    break;
-                case ASSOCIATING:
-                    StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
-                    /* BSSID is valid only in ASSOCIATING state */
-                    mWifiInfo.setBSSID(stateChangeResult.BSSID);
-                    //$FALL-THROUGH$
-                case ASSOCIATED:
-                case FOUR_WAY_HANDSHAKE:
-                case GROUP_HANDSHAKE:
-                    transitionTo(mHandshakeState);
-                    break;
-                case COMPLETED:
-                    transitionTo(mCompletedState);
-                    break;
-                case DORMANT:
-                    transitionTo(mDormantState);
-                    break;
-                case INACTIVE:
-                    transitionTo(mInactiveState);
-                    break;
-                case UNINITIALIZED:
-                case INVALID:
-                    transitionTo(mUninitializedState);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            StateChangeResult stateChangeResult = (StateChangeResult) msg.obj;
-            SupplicantState supState = (SupplicantState) stateChangeResult.state;
-            setDetailedState(WifiInfo.getDetailedStateOf(supState));
-            mWifiInfo.setSupplicantState(supState);
-            mWifiInfo.setNetworkId(stateChangeResult.networkId);
-            //TODO: Modify WifiMonitor to report SSID on events
-            //mWifiInfo.setSSID()
-            return HANDLED;
-        }
-
-        /********************************************************
-         * HSM states
-         *******************************************************/
-
-        class InitializedState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-                switch (message.what) {
-                    case CMD_START_SCAN:
-                        WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
-                        break;
-                    default:
-                        if (DBG) Log.w(TAG, "Ignoring " + message);
-                        break;
-                }
-                return HANDLED;
-            }
-        }
-
-        class UninitializedState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-                 mNetworkInfo.setIsAvailable(false);
-                 resetLoopDetection();
-                 mPasswordKeyMayBeIncorrect = false;
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                switch(message.what) {
-                    default:
-                        if (!handleTransition(message)) {
-                            if (DBG) Log.w(TAG, "Ignoring " + message);
-                        }
-                        break;
-                }
-                return HANDLED;
-            }
-        }
-
-        class InactiveState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-                 Message message = getCurrentMessage();
-                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
-                 mNetworkInfo.setIsAvailable(false);
-                 resetLoopDetection();
-                 mPasswordKeyMayBeIncorrect = false;
-
-                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                return handleTransition(message);
-            }
-        }
-
-
-        class DisconnectedState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-                 Message message = getCurrentMessage();
-                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
-                 mNetworkInfo.setIsAvailable(true);
-                 resetLoopDetection();
-
-                 /* If a disconnect event happens after a password key failure
-                  * event, disable the network
-                  */
-                 if (mPasswordKeyMayBeIncorrect) {
-                     Log.d(TAG, "Failed to authenticate, disabling network " +
-                             mWifiInfo.getNetworkId());
-                     WifiNative.disableNetworkCommand(mWifiInfo.getNetworkId());
-                     mPasswordKeyMayBeIncorrect = false;
-                     sendSupplicantStateChangedBroadcast(stateChangeResult, true);
-                 }
-                 else {
-                     sendSupplicantStateChangedBroadcast(stateChangeResult, false);
-                 }
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                return handleTransition(message);
-            }
-        }
-
-        class ScanState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-                 Message message = getCurrentMessage();
-                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
-                 mNetworkInfo.setIsAvailable(true);
-                 mPasswordKeyMayBeIncorrect = false;
-                 resetLoopDetection();
-                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                return handleTransition(message);
-            }
-        }
-
-        class ConnectState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                switch (message.what) {
-                    case CMD_START_SCAN:
-                        WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE);
-                        WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
-                        break;
-                    default:
-                        return NOT_HANDLED;
-                }
-                return HANDLED;
-            }
-        }
-
-        class HandshakeState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-                 final Message message = getCurrentMessage();
-                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
-                 mNetworkInfo.setIsAvailable(true);
-
-                 if (mLoopDetectIndex > message.what) {
-                     mLoopDetectCount++;
-                 }
-                 if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) {
-                     WifiNative.disableNetworkCommand(stateChangeResult.networkId);
-                     mLoopDetectCount = 0;
-                 }
-
-                 mLoopDetectIndex = message.what;
-
-                 mPasswordKeyMayBeIncorrect = false;
-                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                return handleTransition(message);
-            }
-        }
-
-        class CompletedState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-                 Message message = getCurrentMessage();
-                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
-                 mNetworkInfo.setIsAvailable(true);
-
-                 mRssiPollToken++;
-                 if (mEnableRssiPolling) {
-                     sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
-                             POLL_RSSI_INTERVAL_MSECS);
-                 }
-
-                 resetLoopDetection();
-
-                 mPasswordKeyMayBeIncorrect = false;
-                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                switch(message.what) {
-                    case ASSOCIATING:
-                    case ASSOCIATED:
-                    case FOUR_WAY_HANDSHAKE:
-                    case GROUP_HANDSHAKE:
-                    case COMPLETED:
-                        break;
-                    case CMD_RSSI_POLL:
-                        if (message.arg1 == mRssiPollToken) {
-                            // Get Info and continue polling
-                            requestPolledInfo();
-                            sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
-                                    POLL_RSSI_INTERVAL_MSECS);
-                        } else {
-                            // Polling has completed
-                        }
-                        break;
-                    case CMD_ENABLE_RSSI_POLL:
-                        mRssiPollToken++;
-                        if (mEnableRssiPolling) {
-                            // first poll
-                            requestPolledInfo();
-                            sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0),
-                                    POLL_RSSI_INTERVAL_MSECS);
-                        }
-                        break;
-                    default:
-                        return handleTransition(message);
-                }
-                return HANDLED;
-            }
-        }
-
-        class DormantState extends HierarchicalState {
-            @Override
-             public void enter() {
-                 if (DBG) Log.d(TAG, getName() + "\n");
-                 Message message = getCurrentMessage();
-                 StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-
-                 mNetworkInfo.setIsAvailable(true);
-                 resetLoopDetection();
-                 mPasswordKeyMayBeIncorrect = false;
-
-                 sendSupplicantStateChangedBroadcast(stateChangeResult, false);
-
-                 /* TODO: reconnect is now being handled at DHCP failure handling
-                  * If we run into issues with staying in Dormant state, might
-                  * need a reconnect here
-                  */
-             }
-            @Override
-            public boolean processMessage(Message message) {
-                return handleTransition(message);
-            }
-        }
-    }
-
-    private class NotificationEnabledSettingObserver extends ContentObserver {
-
-        public NotificationEnabledSettingObserver(Handler handler) {
-            super(handler);
-        }
-
-        public void register() {
-            ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
-            mNotificationEnabled = getValue();
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-
-            mNotificationEnabled = getValue();
-            if (!mNotificationEnabled) {
-                // Remove any notification that may be showing
-                setNotificationVisible(false, 0, true, 0);
-            }
-
-            resetNotificationTimer();
-        }
-
-        private boolean getValue() {
-            return Settings.Secure.getInt(mContext.getContentResolver(),
-                    Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
-        }
-    }
-}
+}
\ No newline at end of file