/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.connectivitymanagertest.functional;

import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;

import android.content.Intent;
import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.app.Instrumentation;
import android.os.Handler;
import android.os.Message;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.NetworkInfo.DetailedState;
import android.net.wifi.WifiManager;

import android.test.suitebuilder.annotation.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
import com.android.connectivitymanagertest.NetworkState;
import android.util.Log;

public class ConnectivityManagerMobileTest
    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
    private static final String LOG_TAG = "ConnectivityManagerMobileTest";
    private static final String PKG_NAME = "com.android.connectivitymanagertest";
    private static final long STATE_TRANSITION_SHORT_TIMEOUT = 5 * 1000;
    private static final long STATE_TRANSITION_LONG_TIMEOUT = 30 * 1000;

    private String TEST_ACCESS_POINT;
    private ConnectivityManagerTestActivity cmActivity;
    private WakeLock wl;

    public ConnectivityManagerMobileTest() {
        super(PKG_NAME, ConnectivityManagerTestActivity.class);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        cmActivity = getActivity();
        ConnectivityManagerTestRunner mRunner =
                (ConnectivityManagerTestRunner)getInstrumentation();
        TEST_ACCESS_POINT = mRunner.TEST_SSID;
        PowerManager pm = (PowerManager)getInstrumentation().
                getContext().getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "CMWakeLock");
        wl.acquire();
        // Each test case will start with cellular connection
        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);
        verifyCellularConnection();
    }

    @Override
    public void tearDown() throws Exception {
        cmActivity.finish();
        Log.v(LOG_TAG, "tear down ConnectivityManagerTestActivity");
        wl.release();
        cmActivity.clearWifi();
        super.tearDown();
    }

    // help function to verify 3G connection
    public void verifyCellularConnection() {
        NetworkInfo extraNetInfo = cmActivity.mNetworkInfo;
        assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
            extraNetInfo.getType());
        assertTrue("not connected to cellular network", extraNetInfo.isConnected());
        assertTrue("no data connection", cmActivity.mState.equals(State.CONNECTED));
    }

    // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED,
    //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
    private void waitForNetworkState(int networkType, State expectedState, long timeout) {
        long startTime = System.currentTimeMillis();
        // In case the broadcast is already sent out, no need to wait
        if (cmActivity.mCM.getNetworkInfo(networkType).getState() == expectedState) {
            return;
        } else {
            while (true) {
                if ((System.currentTimeMillis() - startTime) > timeout) {
                    assertFalse("Wait for network state timeout", true);
                }
                Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
                        " to be " + expectedState.toString());
                synchronized (cmActivity.connectivityObject) {
                    try {
                        cmActivity.connectivityObject.wait(STATE_TRANSITION_SHORT_TIMEOUT);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if ((cmActivity.mNetworkInfo.getType() != networkType) ||
                        (cmActivity.mNetworkInfo.getState() != expectedState)) {
                        Log.v(LOG_TAG, "network state for " + cmActivity.mNetworkInfo.getType() +
                                "is: " + cmActivity.mNetworkInfo.getState());
                        continue;
                    }
                    break;
                }
            }
        }
    }

    // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
    //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
    private void waitForWifiState(int expectedState, long timeout) {
        long startTime = System.currentTimeMillis();
        if (cmActivity.mWifiState == expectedState) {
            return;
        } else {
            while (true) {
                if ((System.currentTimeMillis() - startTime) > timeout) {
                    assertFalse("Wait for Wifi state timeout", true);
                }
                Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
                synchronized (cmActivity.wifiObject) {
                    try {
                        cmActivity.wifiObject.wait(5*1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (cmActivity.mWifiState != expectedState) {
                        Log.v(LOG_TAG, "Wifi state is: " + cmActivity.mWifiNetworkInfo.getState());
                        continue;
                    }
                    break;
                }
            }
        }
    }

    // Test case 1: Test enabling Wifi without associating with any AP
    @LargeTest
    public void test3GToWifiNotification() {
        // To avoid UNKNOWN state when device boots up
        cmActivity.enableWifi();
        try {
            Thread.sleep(2 * STATE_TRANSITION_SHORT_TIMEOUT);
        } catch (Exception e) {
            Log.v(LOG_TAG, "exception: " + e.toString());
        }

        cmActivity.disableWifi();
        // As Wifi stays in DISCONNECTED, the connectivity manager will not broadcast
        // any network connectivity event for Wifi
        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE, networkInfo.getState(),
                NetworkState.DO_NOTHING, State.CONNECTED);
        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                NetworkState.DO_NOTHING, State.DISCONNECTED);
        // Eanble Wifi
        cmActivity.enableWifi();
        try {
            Thread.sleep(2 * STATE_TRANSITION_SHORT_TIMEOUT);
        } catch (Exception e) {
            Log.v(LOG_TAG, "exception: " + e.toString());
        }

        // validate state and broadcast
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
            Log.v(LOG_TAG, "the state for WIFI is changed");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
            assertTrue("state validation fail", false);
        }
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
            Log.v(LOG_TAG, "the state for MOBILE is changed");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
            assertTrue("state validation fail", false);
        }
        // Verify that the device is still connected to MOBILE
        verifyCellularConnection();
    }

    // Test case 2: test connection to a given AP
    @LargeTest
    public void testConnectToWifi() {
        assertNotNull("SSID is null", TEST_ACCESS_POINT);
        //Prepare for connectivity verification
        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE, networkInfo.getState(),
                NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                NetworkState.TO_CONNECTION, State.CONNECTED);

        // Enable Wifi and connect to a test access point
        assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                cmActivity.connectToWifi(TEST_ACCESS_POINT));

        waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
        Log.v(LOG_TAG, "wifi state is enabled");
        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);
        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        // validate states
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
            Log.v(LOG_TAG, "Wifi state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
            assertTrue(false);
        }
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
            Log.v(LOG_TAG, "Mobile state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
            assertTrue(false);
        }
    }

    // Test case 3: connect to Wifi with known AP
    @LargeTest
    public void testConnectToWifWithKnownAP() {
        assertNotNull("SSID is null", TEST_ACCESS_POINT);
        // Connect to TEST_ACCESS_POINT
        assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                cmActivity.connectToWifi(TEST_ACCESS_POINT));
        waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        try {
            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
        } catch (Exception e) {
            Log.v(LOG_TAG, "exception: " + e.toString());
        }

        // Disable Wifi
        Log.v(LOG_TAG, "Disable Wifi");
        if (!cmActivity.disableWifi()) {
            Log.v(LOG_TAG, "disable Wifi failed");
            return;
        }

        // Wait for the Wifi state to be DISABLED
        waitForWifiState(WifiManager.WIFI_STATE_DISABLED, STATE_TRANSITION_LONG_TIMEOUT);
        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);
        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        //Prepare for connectivity state verification
        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                              networkInfo.getState(), NetworkState.DO_NOTHING,
                                              State.DISCONNECTED);
        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                NetworkState.TO_CONNECTION, State.CONNECTED);

        // Enable Wifi again
        Log.v(LOG_TAG, "Enable Wifi again");
        cmActivity.enableWifi();

        // Wait for Wifi to be connected and mobile to be disconnected
        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);
        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        // validate wifi states
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
            Log.v(LOG_TAG, "Wifi state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
            assertTrue(false);
        }
    }

    // Test case 4:  test disconnect Wifi
    @LargeTest
    public void testDisconnectWifi() {
        assertNotNull("SSID is null", TEST_ACCESS_POINT);

        // connect to Wifi
        assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                   cmActivity.connectToWifi(TEST_ACCESS_POINT));

        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
            STATE_TRANSITION_LONG_TIMEOUT);

        // Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
        try {
            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
        } catch (Exception e) {
            Log.v(LOG_TAG, "exception: " + e.toString());
        }

        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                              networkInfo.getState(),
                                              NetworkState.TO_CONNECTION,
                                              State.CONNECTED);
        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                NetworkState.TO_DISCONNECTION, State.DISCONNECTED);

        // clear Wifi
        cmActivity.clearWifi();

        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);
        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        // validate states
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
            Log.v(LOG_TAG, "Wifi state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
            assertTrue(false);
        }
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
            Log.v(LOG_TAG, "Mobile state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
            assertTrue(false);
        }
    }

    // Test case 5: test connectivity from 3G to airplane mode, then to 3G again
    @LargeTest
    public void testDataConnectionWith3GToAmTo3G() {
        //Prepare for state verification
        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                              networkInfo.getState(),
                                              NetworkState.TO_DISCONNECTION,
                                              State.DISCONNECTED);
        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        assertEquals(State.DISCONNECTED, networkInfo.getState());
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                NetworkState.DO_NOTHING, State.DISCONNECTED);

        // Enable airplane mode
        cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
        try {
            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
        } catch (Exception e) {
            Log.v(LOG_TAG, "exception: " + e.toString());
        }

        // Validate the state transition
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
            Log.v(LOG_TAG, "Wifi state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
            assertTrue(false);
        }
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
            Log.v(LOG_TAG, "Mobile state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
            assertTrue(false);
        }

        // reset state recorder
        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                              networkInfo.getState(),
                                              NetworkState.TO_CONNECTION,
                                              State.CONNECTED);
        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                NetworkState.DO_NOTHING, State.DISCONNECTED);

        // disable airplane mode
        cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);

        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        // Validate the state transition
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
            Log.v(LOG_TAG, "Mobile state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
            assertTrue(false);
        }
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
          Log.v(LOG_TAG, "Wifi state transition validation failed.");
          Log.v(LOG_TAG, "reason: " +
                  cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
          assertTrue(false);
        }
    }

    // Test case 6: test connectivity with airplane mode Wifi connected
    @LargeTest
    public void testDataConnectionOverAMWithWifi() {
        assertNotNull("SSID is null", TEST_ACCESS_POINT);
        // Eanble airplane mode
        cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);

        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                              networkInfo.getState(),
                                              NetworkState.DO_NOTHING,
                                              State.DISCONNECTED);
        networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
                                              NetworkState.TO_CONNECTION, State.CONNECTED);

        // Connect to Wifi
        assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                   cmActivity.connectToWifi(TEST_ACCESS_POINT));
        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                            STATE_TRANSITION_LONG_TIMEOUT);

        // validate state and broadcast
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
            Log.v(LOG_TAG, "state validate for Wifi failed");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
            assertTrue("State validation failed", false);
        }
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
            Log.v(LOG_TAG, "state validation for Mobile failed");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
            assertTrue("state validation failed", false);
        }
        cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
    }

    // Test case 7: test connectivity while transit from Wifi->AM->Wifi
    @LargeTest
    public void testDataConnectionWithWifiToAMToWifi () {
        // Connect to TEST_ACCESS_POINT
        assertNotNull("SSID is null", TEST_ACCESS_POINT);
        // Connect to Wifi
        assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                cmActivity.connectToWifi(TEST_ACCESS_POINT));

        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        try {
            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
        } catch (Exception e) {
            Log.v(LOG_TAG, "exception: " + e.toString());
        }

        // Enable airplane mode without clearing Wifi
        cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);

        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        try {
            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
        } catch (Exception e) {
            Log.v(LOG_TAG, "exception: " + e.toString());
        }

        // Prepare for state validation
        NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        assertEquals(State.DISCONNECTED, networkInfo.getState());
        cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
                networkInfo.getState(), NetworkState.TO_CONNECTION, State.CONNECTED);

        // Disable airplane mode
        cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);

        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                            STATE_TRANSITION_LONG_TIMEOUT);
        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.DISCONNECTED,
                            STATE_TRANSITION_LONG_TIMEOUT);

        // validate the state transition
        if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
            Log.v(LOG_TAG, "Wifi state transition validation failed.");
            Log.v(LOG_TAG, "reason: " +
                    cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
            assertTrue(false);
        }
    }

    // Test case 8: test wifi state change while connecting/disconnecting to/from an AP
    @LargeTest
    public void testWifiStateChange () {
        assertNotNull("SSID is null", TEST_ACCESS_POINT);
        //Connect to TEST_ACCESS_POINT
        assertTrue("failed to connect to " + TEST_ACCESS_POINT,
                   cmActivity.connectToWifi(TEST_ACCESS_POINT));
        waitForWifiState(WifiManager.WIFI_STATE_ENABLED, STATE_TRANSITION_LONG_TIMEOUT);
        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                            STATE_TRANSITION_LONG_TIMEOUT);
        assertNotNull("Not associated with any AP",
                      cmActivity.mWifiManager.getConnectionInfo().getBSSID());

        try {
            Thread.sleep(STATE_TRANSITION_SHORT_TIMEOUT);
        } catch (Exception e) {
            Log.v(LOG_TAG, "exception: " + e.toString());
        }

        // Disconnect from the current AP
        Log.v(LOG_TAG, "disconnect from the AP");
        if (!cmActivity.disconnectAP()) {
            Log.v(LOG_TAG, "failed to disconnect from " + TEST_ACCESS_POINT);
        }

        // Verify the connectivity state for Wifi is DISCONNECTED
        waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                STATE_TRANSITION_LONG_TIMEOUT);

        if (!cmActivity.disableWifi()) {
            Log.v(LOG_TAG, "disable Wifi failed");
            return;
        }
        waitForWifiState(WifiManager.WIFI_STATE_DISABLED, STATE_TRANSITION_LONG_TIMEOUT);
    }
}
