ConnectivityManagerTestActivity.java revision ca1f2b1a1e8cb785be5ebbcf7ded7c921cbf80a7
1/*
2 * Copyright (C) 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.connectivitymanagertest;
18
19import com.android.connectivitymanagertest.R;
20import android.app.Activity;
21import android.content.Context;
22import android.content.res.Resources;
23import android.content.BroadcastReceiver;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.os.Bundle;
27import android.provider.Settings;
28import android.util.Log;
29import android.view.KeyEvent;
30
31import java.io.InputStream;
32import java.util.ArrayList;
33import java.util.List;
34import android.widget.LinearLayout;
35import android.net.ConnectivityManager;
36import android.net.NetworkInfo;
37import android.net.NetworkInfo.State;
38
39import android.net.wifi.SupplicantState;
40import android.net.wifi.WifiConfiguration;
41import android.net.wifi.WifiManager;
42import android.net.wifi.WifiInfo;
43import android.net.wifi.ScanResult;
44import android.net.wifi.WifiConfiguration.KeyMgmt;
45
46/**
47 * An activity registered with connectivity manager broadcast
48 * provides network connectivity information and
49 * can be used to set device states: Cellular, Wifi, Airplane mode.
50 */
51public class ConnectivityManagerTestActivity extends Activity {
52
53    public static final String LOG_TAG = "ConnectivityManagerTestActivity";
54    public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
55    public static final int WIFI_SCAN_TIMEOUT = 20 * 1000;
56    public static final int SHORT_TIMEOUT = 5 * 1000;
57    public static final long LONG_TIMEOUT = 50 * 1000;
58    private static final String ACCESS_POINT_FILE = "accesspoints.xml";
59    public ConnectivityReceiver mConnectivityReceiver = null;
60    public WifiReceiver mWifiReceiver = null;
61    /*
62     * Track network connectivity information
63     */
64    public State mState;
65    public NetworkInfo mNetworkInfo;
66    public NetworkInfo mOtherNetworkInfo;
67    public boolean mIsFailOver;
68    public String mReason;
69    public boolean mScanResultIsAvailable = false;
70    public ConnectivityManager mCM;
71    public Object wifiObject = new Object();
72    public Object connectivityObject = new Object();
73    public int mWifiState;
74    public NetworkInfo mWifiNetworkInfo;
75    public String mBssid;
76    public String mPowerSsid = "GoogleGuest"; //Default power SSID
77    private Context mContext;
78
79    /*
80     * Control Wifi States
81     */
82    public WifiManager mWifiManager;
83
84    /*
85     * Verify connectivity state
86     */
87    public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
88    NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
89
90    /**
91     * A wrapper of a broadcast receiver which provides network connectivity information
92     * for all kinds of network: wifi, mobile, etc.
93     */
94    private class ConnectivityReceiver extends BroadcastReceiver {
95        @Override
96        public void onReceive(Context context, Intent intent) {
97            Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent);
98            String action = intent.getAction();
99            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
100                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
101                return;
102            }
103
104            boolean noConnectivity =
105                intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
106
107            if (noConnectivity) {
108                mState = State.DISCONNECTED;
109            } else {
110                mState = State.CONNECTED;
111            }
112
113            mNetworkInfo = (NetworkInfo)
114                intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
115
116            mOtherNetworkInfo = (NetworkInfo)
117                intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
118
119            mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
120            mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
121
122            Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString());
123            if (mOtherNetworkInfo != null) {
124                Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
125            }
126            recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
127            if (mOtherNetworkInfo != null) {
128                recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
129            }
130            notifyNetworkConnectivityChange();
131        }
132    }
133
134    private class WifiReceiver extends BroadcastReceiver {
135        @Override
136        public void onReceive(Context context, Intent intent) {
137            String action = intent.getAction();
138            Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
139            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
140                notifyScanResult();
141            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
142                mWifiNetworkInfo =
143                    (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
144                Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
145                if (mWifiNetworkInfo.getState() == State.CONNECTED) {
146                    mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
147                }
148                notifyWifiState();
149            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
150                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
151                                                WifiManager.WIFI_STATE_UNKNOWN);
152                notifyWifiState();
153            }
154            else {
155                return;
156            }
157        }
158    }
159
160    public ConnectivityManagerTestActivity() {
161        mState = State.UNKNOWN;
162    }
163
164    @Override
165    protected void onCreate(Bundle savedInstanceState) {
166        super.onCreate(savedInstanceState);
167        Log.v(LOG_TAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
168
169        // Create a simple layout
170        LinearLayout contentView = new LinearLayout(this);
171        contentView.setOrientation(LinearLayout.VERTICAL);
172        setContentView(contentView);
173        setTitle("ConnectivityManagerTestActivity");
174
175
176        // register a connectivity receiver for CONNECTIVITY_ACTION;
177        mConnectivityReceiver = new ConnectivityReceiver();
178        registerReceiver(mConnectivityReceiver,
179                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
180
181        mWifiReceiver = new WifiReceiver();
182        IntentFilter mIntentFilter = new IntentFilter();
183        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
184        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
185        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
186        mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
187        registerReceiver(mWifiReceiver, mIntentFilter);
188
189        // Get an instance of ConnectivityManager
190        mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
191        // Get an instance of WifiManager
192        mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
193        initializeNetworkStates();
194
195        if (mWifiManager.isWifiEnabled()) {
196            Log.v(LOG_TAG, "Clear Wifi before we start the test.");
197            removeConfiguredNetworksAndDisableWifi();
198        }
199     }
200
201    public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
202        InputStream in = getAssets().open(ACCESS_POINT_FILE);
203        AccessPointParserHelper parseHelper = new AccessPointParserHelper();
204        return parseHelper.processAccessPoint(in);
205    }
206
207    private void printNetConfig(String[] configuration) {
208        for (int i = 0; i < configuration.length; i++) {
209            if (i == 0) {
210                Log.v(LOG_TAG, "SSID: " + configuration[0]);
211            } else {
212                Log.v(LOG_TAG, "      " + configuration[i]);
213            }
214        }
215    }
216
217    // for each network type, initialize network states to UNKNOWN, and no verification flag is set
218    public void initializeNetworkStates() {
219        for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
220            connectivityState[networkType] =  new NetworkState();
221            Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " +
222                    connectivityState[networkType].toString());
223        }
224    }
225
226    // deposit a network state
227    public void recordNetworkState(int networkType, State networkState) {
228        Log.v(LOG_TAG, "record network state for network " +  networkType +
229                ", state is " + networkState);
230        connectivityState[networkType].recordState(networkState);
231    }
232
233    // set the state transition criteria
234    public void setStateTransitionCriteria(int networkType, State initState,
235            int transitionDir, State targetState) {
236        connectivityState[networkType].setStateTransitionCriteria(
237                initState, transitionDir, targetState);
238    }
239
240    // Validate the states recorded
241    public boolean validateNetworkStates(int networkType) {
242        Log.v(LOG_TAG, "validate network state for " + networkType + ": ");
243        return connectivityState[networkType].validateStateTransition();
244    }
245
246    // return result from network state validation
247    public String getTransitionFailureReason(int networkType) {
248        Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " +
249                connectivityState[networkType].toString());
250        return connectivityState[networkType].getReason();
251    }
252
253    private void notifyNetworkConnectivityChange() {
254        synchronized(connectivityObject) {
255            Log.v(LOG_TAG, "notify network connectivity changed");
256            connectivityObject.notifyAll();
257        }
258    }
259    private void notifyScanResult() {
260        synchronized (this) {
261            Log.v(LOG_TAG, "notify that scan results are available");
262            this.notify();
263        }
264    }
265
266    public void notifyWifiState() {
267        synchronized (wifiObject) {
268            Log.v(LOG_TAG, "notify wifi state changed");
269            wifiObject.notify();
270        }
271    }
272
273    // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED,
274    //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
275    public boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
276        long startTime = System.currentTimeMillis();
277        while (true) {
278            if ((System.currentTimeMillis() - startTime) > timeout) {
279                if (mCM.getNetworkInfo(networkType).getState() != expectedState) {
280                    return false;
281                } else {
282                    // the broadcast has been sent out. the state has been changed.
283                    Log.v(LOG_TAG, "networktype: " + networkType + " state: " +
284                            mCM.getNetworkInfo(networkType));
285                    return true;
286                }
287            }
288            Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
289                    " to be " + expectedState.toString());
290            synchronized (connectivityObject) {
291                try {
292                    connectivityObject.wait(SHORT_TIMEOUT);
293                } catch (InterruptedException e) {
294                    e.printStackTrace();
295                }
296                if ((mNetworkInfo.getType() != networkType) ||
297                    (mNetworkInfo.getState() != expectedState)) {
298                    Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() +
299                            "is: " + mNetworkInfo.getState());
300                    continue;
301                }
302                return true;
303            }
304        }
305    }
306
307    // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
308    //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
309    public boolean waitForWifiState(int expectedState, long timeout) {
310        long startTime = System.currentTimeMillis();
311        while (true) {
312            if ((System.currentTimeMillis() - startTime) > timeout) {
313                if (mWifiState != expectedState) {
314                    return false;
315                } else {
316                    return true;
317                }
318            }
319            Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
320            synchronized (wifiObject) {
321                try {
322                    wifiObject.wait(SHORT_TIMEOUT);
323                } catch (InterruptedException e) {
324                    e.printStackTrace();
325                }
326                if (mWifiState != expectedState) {
327                    Log.v(LOG_TAG, "Wifi state is: " + mWifiNetworkInfo.getState());
328                    continue;
329                }
330                return true;
331            }
332        }
333    }
334
335    // Return true if device is currently connected to mobile network
336    public boolean isConnectedToMobile() {
337        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
338    }
339
340    // Return true if device is currently connected to Wifi
341    public boolean isConnectedToWifi() {
342        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
343    }
344
345    public boolean enableWifi() {
346        return mWifiManager.setWifiEnabled(true);
347    }
348
349    /**
350     * Associate the device to given SSID
351     * If the device is already associated with a WiFi, disconnect and forget it,
352     * We don't verify whether the connection is successful or not, leave this to the test
353     */
354    public boolean connectToWifi(String knownSSID) {
355        WifiConfiguration config = new WifiConfiguration();
356        config.SSID = knownSSID;
357        config.allowedKeyManagement.set(KeyMgmt.NONE);
358        return connectToWifiWithConfiguration(config);
359    }
360
361    /**
362     * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration
363     * is pure string, we need to convert it to quoted string.
364     * @param config
365     * @return
366     */
367    public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
368        String ssid = config.SSID;
369        config.SSID = convertToQuotedString(ssid);
370
371        //If Wifi is not enabled, enable it
372        if (!mWifiManager.isWifiEnabled()) {
373            Log.v(LOG_TAG, "Wifi is not enabled, enable it");
374            mWifiManager.setWifiEnabled(true);
375        }
376
377        List<ScanResult> netList = mWifiManager.getScanResults();
378        if (netList == null) {
379            Log.v(LOG_TAG, "scan results are null");
380            // if no scan results are available, start active scan
381            mWifiManager.startScanActive();
382            mScanResultIsAvailable = false;
383            long startTime = System.currentTimeMillis();
384            while (!mScanResultIsAvailable) {
385                if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
386                    return false;
387                }
388                // wait for the scan results to be available
389                synchronized (this) {
390                    // wait for the scan result to be available
391                    try {
392                        this.wait(WAIT_FOR_SCAN_RESULT);
393                    } catch (InterruptedException e) {
394                        e.printStackTrace();
395                    }
396                    if ((mWifiManager.getScanResults() == null) ||
397                            (mWifiManager.getScanResults().size() <= 0)) {
398                        continue;
399                    }
400                    mScanResultIsAvailable = true;
401                }
402            }
403        }
404
405        netList = mWifiManager.getScanResults();
406
407        for (int i = 0; i < netList.size(); i++) {
408            ScanResult sr= netList.get(i);
409            if (sr.SSID.equals(ssid)) {
410                Log.v(LOG_TAG, "found " + ssid + " in the scan result list");
411                int networkId = mWifiManager.addNetwork(config);
412                // Connect to network by disabling others.
413                mWifiManager.enableNetwork(networkId, true);
414                mWifiManager.saveConfiguration();
415                List<WifiConfiguration> wifiNetworks = mWifiManager.getConfiguredNetworks();
416                for (WifiConfiguration netConfig : wifiNetworks) {
417                    Log.v(LOG_TAG, netConfig.toString());
418                }
419
420                mWifiManager.reconnect();
421                break;
422           }
423        }
424
425        List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
426        if (netConfList.size() <= 0) {
427            Log.v(LOG_TAG, ssid + " is not available");
428            return false;
429        }
430        return true;
431    }
432
433    /*
434     * Disconnect from the current AP and remove configured networks.
435     */
436    public boolean disconnectAP() {
437        if (mWifiManager.isWifiEnabled()) {
438            //remove the current network Id
439            WifiInfo curWifi = mWifiManager.getConnectionInfo();
440            if (curWifi == null) {
441                return false;
442            }
443            int curNetworkId = curWifi.getNetworkId();
444            mWifiManager.removeNetwork(curNetworkId);
445            mWifiManager.saveConfiguration();
446
447            // remove other saved networks
448            List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
449            if (netConfList != null) {
450                Log.v(LOG_TAG, "remove configured network ids");
451                for (int i = 0; i < netConfList.size(); i++) {
452                    WifiConfiguration conf = new WifiConfiguration();
453                    conf = netConfList.get(i);
454                    mWifiManager.removeNetwork(conf.networkId);
455                }
456            }
457        }
458        mWifiManager.saveConfiguration();
459        return true;
460    }
461    /**
462     * Disable Wifi
463     * @return true if Wifi is disabled successfully
464     */
465    public boolean disableWifi() {
466        return mWifiManager.setWifiEnabled(false);
467    }
468
469    /**
470     * Remove configured networks and disable wifi
471     */
472    public boolean removeConfiguredNetworksAndDisableWifi() {
473            if (!disconnectAP()) {
474                return false;
475            }
476            // Disable Wifi
477            if (!mWifiManager.setWifiEnabled(false)) {
478                return false;
479            }
480            // Wait for the actions to be completed
481            try {
482                Thread.sleep(5*1000);
483            } catch (InterruptedException e) {}
484        return true;
485    }
486
487    /**
488     * Set airplane mode
489     */
490    public void setAirplaneMode(Context context, boolean enableAM) {
491        //set the airplane mode
492        Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
493                enableAM ? 1 : 0);
494        // Post the intent
495        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
496        intent.putExtra("state", enableAM);
497        context.sendBroadcast(intent);
498    }
499
500    protected static String convertToQuotedString(String string) {
501        return "\"" + string + "\"";
502    }
503
504    @Override
505    protected void onDestroy() {
506        super.onDestroy();
507
508        //Unregister receiver
509        if (mConnectivityReceiver != null) {
510            unregisterReceiver(mConnectivityReceiver);
511        }
512        if (mWifiReceiver != null) {
513            unregisterReceiver(mWifiReceiver);
514        }
515        Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
516    }
517
518    @Override
519    public void onStart() {
520        super.onStart();
521        mContext = this;
522        Bundle bundle = this.getIntent().getExtras();
523        if (bundle != null){
524            mPowerSsid = bundle.getString("power_ssid");
525        }
526    }
527    //A thread to set the device into airplane mode then turn on wifi.
528    Thread setDeviceWifiAndAirplaneThread = new Thread(new Runnable() {
529        public void run() {
530            setAirplaneMode(mContext, true);
531            connectToWifi(mPowerSsid);
532        }
533    });
534
535    //A thread to set the device into wifi
536    Thread setDeviceInWifiOnlyThread = new Thread(new Runnable() {
537        public void run() {
538            connectToWifi(mPowerSsid);
539        }
540    });
541
542    @Override
543    public boolean onKeyDown(int keyCode, KeyEvent event) {
544        switch (keyCode) {
545            //This is a tricky way for the scripted monkey to
546            //set the device in wifi and wifi in airplane mode.
547            case KeyEvent.KEYCODE_1:
548                setDeviceWifiAndAirplaneThread.start();
549                break;
550
551            case KeyEvent.KEYCODE_2:
552                setDeviceInWifiOnlyThread.start();
553                break;
554        }
555        return super.onKeyDown(keyCode, event);
556    }
557}
558