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 android.app.Activity;
20import android.content.Context;
21import android.content.BroadcastReceiver;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.os.Bundle;
25import android.provider.Settings;
26import android.util.Log;
27import java.util.List;
28import android.widget.LinearLayout;
29import android.net.ConnectivityManager;
30import android.net.NetworkInfo;
31import android.net.NetworkInfo.State;
32
33import android.net.wifi.WifiConfiguration;
34import android.net.wifi.WifiManager;
35import android.net.wifi.WifiInfo;
36import android.net.wifi.ScanResult;
37import android.net.wifi.WifiConfiguration.KeyMgmt;
38
39
40/**
41 * An activity registered with connectivity manager broadcast
42 * provides network connectivity information and
43 * can be used to set device states: Cellular, Wifi, Airplane mode.
44 */
45public class ConnectivityManagerTestActivity extends Activity {
46
47    public static final String LOG_TAG = "ConnectivityManagerTestActivity";
48    public static final int WAIT_FOR_SCAN_RESULT = 5 * 1000; //5 seconds
49    public static final int WIFI_SCAN_TIMEOUT = 20 * 1000;
50    public ConnectivityReceiver mConnectivityReceiver = null;
51    public WifiReceiver mWifiReceiver = null;
52    /*
53     * Track network connectivity information
54     */
55    public State mState;
56    public NetworkInfo mNetworkInfo;
57    public NetworkInfo mOtherNetworkInfo;
58    public boolean mIsFailOver;
59    public String mReason;
60    public boolean mScanResultIsAvailable = false;
61    public ConnectivityManager mCM;
62    public Object wifiObject = new Object();
63    public Object connectivityObject = new Object();
64    public int mWifiState;
65    public NetworkInfo mWifiNetworkInfo;
66    public String mBssid;
67
68    /*
69     * Control Wifi States
70     */
71    public WifiManager mWifiManager;
72
73    /*
74     * Verify connectivity state
75     */
76    public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
77    NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
78
79    /**
80     * A wrapper of a broadcast receiver which provides network connectivity information
81     * for all kinds of network: wifi, mobile, etc.
82     */
83    private class ConnectivityReceiver extends BroadcastReceiver {
84        @Override
85        public void onReceive(Context context, Intent intent) {
86            Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent);
87            String action = intent.getAction();
88            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
89                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
90                return;
91            }
92
93            boolean noConnectivity =
94                intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
95
96            if (noConnectivity) {
97                mState = State.DISCONNECTED;
98            } else {
99                mState = State.CONNECTED;
100            }
101
102            mNetworkInfo = (NetworkInfo)
103                intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
104
105            mOtherNetworkInfo = (NetworkInfo)
106                intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
107
108            mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
109            mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
110
111            Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString());
112            if (mOtherNetworkInfo != null) {
113                Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
114            }
115            recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
116            if (mOtherNetworkInfo != null) {
117                recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
118            }
119            notifyNetworkConnectivityChange();
120        }
121    }
122
123    private class WifiReceiver extends BroadcastReceiver {
124        @Override
125        public void onReceive(Context context, Intent intent) {
126            String action = intent.getAction();
127            Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
128            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
129                notifyScanResult();
130            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
131                mWifiNetworkInfo =
132                    (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
133                Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
134                if (mWifiNetworkInfo.getState() == State.CONNECTED) {
135                    mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
136                }
137                notifyWifiState();
138            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
139                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
140                                                WifiManager.WIFI_STATE_UNKNOWN);
141                notifyWifiState();
142            }
143            else {
144                return;
145            }
146        }
147    }
148
149    public ConnectivityManagerTestActivity() {
150        mState = State.UNKNOWN;
151    }
152
153    @Override
154    protected void onCreate(Bundle savedInstanceState) {
155        super.onCreate(savedInstanceState);
156        Log.v(LOG_TAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
157
158        // Create a simple layout
159        LinearLayout contentView = new LinearLayout(this);
160        contentView.setOrientation(LinearLayout.VERTICAL);
161        setContentView(contentView);
162        setTitle("ConnectivityManagerTestActivity");
163
164
165        // register a connectivity receiver for CONNECTIVITY_ACTION;
166        mConnectivityReceiver = new ConnectivityReceiver();
167        registerReceiver(mConnectivityReceiver,
168                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
169
170        mWifiReceiver = new WifiReceiver();
171        IntentFilter mIntentFilter = new IntentFilter();
172        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
173        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
174        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
175        registerReceiver(mWifiReceiver, mIntentFilter);
176
177        // Get an instance of ConnectivityManager
178        mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
179        // Get an instance of WifiManager
180        mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
181        initializeNetworkStates();
182
183        if (mWifiManager.isWifiEnabled()) {
184            Log.v(LOG_TAG, "Clear Wifi before we start the test.");
185            clearWifi();
186        }
187     }
188
189    // for each network type, initialize network states to UNKNOWN, and no verification flag is set
190    public void initializeNetworkStates() {
191        for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
192            connectivityState[networkType] =  new NetworkState();
193            Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " +
194                    connectivityState[networkType].toString());
195        }
196    }
197
198    // deposit a network state
199    public void recordNetworkState(int networkType, State networkState) {
200        Log.v(LOG_TAG, "record network state for network " +  networkType +
201                ", state is " + networkState);
202        connectivityState[networkType].recordState(networkState);
203    }
204
205    // set the state transition criteria
206    public void setStateTransitionCriteria(int networkType, State initState,
207            int transitionDir, State targetState) {
208        connectivityState[networkType].setStateTransitionCriteria(
209                initState, transitionDir, targetState);
210    }
211
212    // Validate the states recorded
213    public boolean validateNetworkStates(int networkType) {
214        Log.v(LOG_TAG, "validate network state for " + networkType + ": ");
215        return connectivityState[networkType].validateStateTransition();
216    }
217
218    // return result from network state validation
219    public String getTransitionFailureReason(int networkType) {
220        Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " +
221                connectivityState[networkType].toString());
222        return connectivityState[networkType].getReason();
223    }
224
225    private void notifyNetworkConnectivityChange() {
226        synchronized(connectivityObject) {
227            Log.v(LOG_TAG, "notify network connectivity changed");
228            connectivityObject.notifyAll();
229        }
230    }
231    private void notifyScanResult() {
232        synchronized (this) {
233            Log.v(LOG_TAG, "notify that scan results are available");
234            this.notify();
235        }
236    }
237
238    public void notifyWifiState() {
239        synchronized (wifiObject) {
240            Log.v(LOG_TAG, "notify wifi state changed");
241            wifiObject.notify();
242        }
243    }
244
245    // Return true if device is currently connected to mobile network
246    public boolean isConnectedToMobile() {
247        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
248    }
249
250    // Return true if device is currently connected to Wifi
251    public boolean isConnectedToWifi() {
252        return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
253    }
254
255    public boolean enableWifi() {
256        return mWifiManager.setWifiEnabled(true);
257    }
258
259    /**
260     * Associate the device to given SSID
261     * If the device is already associated with a WiFi, disconnect and forget it,
262     * We don't verify whether the connection is successful or not, leave this to the test
263     */
264    public boolean connectToWifi(String knownSSID) {
265        //If Wifi is not enabled, enable it
266        if (!mWifiManager.isWifiEnabled()) {
267            Log.v(LOG_TAG, "Wifi is not enabled, enable it");
268            mWifiManager.setWifiEnabled(true);
269        }
270
271        List<ScanResult> netList = mWifiManager.getScanResults();
272        if (netList == null) {
273            // if no scan results are available, start active scan
274            mWifiManager.startScanActive();
275            mScanResultIsAvailable = false;
276            long startTime = System.currentTimeMillis();
277            while (!mScanResultIsAvailable) {
278                if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
279                    return false;
280                }
281                // wait for the scan results to be available
282                synchronized (this) {
283                    // wait for the scan result to be available
284                    try {
285                        this.wait(WAIT_FOR_SCAN_RESULT);
286                    } catch (InterruptedException e) {
287                        e.printStackTrace();
288                    }
289                    if ((mWifiManager.getScanResults() == null) ||
290                            (mWifiManager.getScanResults().size() <= 0)) {
291                        continue;
292                    }
293                    mScanResultIsAvailable = true;
294                }
295            }
296        }
297
298        netList = mWifiManager.getScanResults();
299        for (int i = 0; i < netList.size(); i++) {
300            ScanResult sr= netList.get(i);
301            if (sr.SSID.equals(knownSSID)) {
302                Log.v(LOG_TAG, "found " + knownSSID + " in the scan result list");
303                WifiConfiguration config = new WifiConfiguration();
304                config.SSID = convertToQuotedString(sr.SSID);
305                config.allowedKeyManagement.set(KeyMgmt.NONE);
306                int networkId = mWifiManager.addNetwork(config);
307                // Connect to network by disabling others.
308                mWifiManager.enableNetwork(networkId, true);
309                mWifiManager.saveConfiguration();
310                mWifiManager.reconnect();
311                break;
312           }
313        }
314
315        List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
316        if (netConfList.size() <= 0) {
317            Log.v(LOG_TAG, knownSSID + " is not available");
318            return false;
319        }
320        return true;
321    }
322
323    /*
324     * Disconnect from the current AP
325     */
326    public boolean disconnectAP() {
327        if (mWifiManager.isWifiEnabled()) {
328            //remove the current network Id
329            WifiInfo curWifi = mWifiManager.getConnectionInfo();
330            if (curWifi == null) {
331                return false;
332            }
333            int curNetworkId = curWifi.getNetworkId();
334            mWifiManager.removeNetwork(curNetworkId);
335            mWifiManager.saveConfiguration();
336
337            // remove other saved networks
338            List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
339            if (netConfList != null) {
340                Log.v(LOG_TAG, "remove configured network ids");
341                for (int i = 0; i < netConfList.size(); i++) {
342                    WifiConfiguration conf = new WifiConfiguration();
343                    conf = netConfList.get(i);
344                    mWifiManager.removeNetwork(conf.networkId);
345                }
346            }
347        }
348        mWifiManager.saveConfiguration();
349        return true;
350    }
351    /**
352     * Disable Wifi
353     * @return true if Wifi is disabled successfully
354     */
355    public boolean disableWifi() {
356        return mWifiManager.setWifiEnabled(false);
357    }
358
359    /**
360     * Disconnect from the current Wifi and clear the configuration list
361     */
362    public boolean clearWifi() {
363            if (!disconnectAP()) {
364                return false;
365            }
366            // Disable Wifi
367            if (!mWifiManager.setWifiEnabled(false)) {
368                return false;
369            }
370            // Wait for the actions to be completed
371            try {
372                Thread.sleep(5*1000);
373            } catch (InterruptedException e) {}
374        return true;
375    }
376
377    /**
378     * Set airplane mode
379     */
380    public void setAirplaneMode(Context context, boolean enableAM) {
381        //set the airplane mode
382        Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
383                enableAM ? 1 : 0);
384        // Post the intent
385        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
386        intent.putExtra("state", enableAM);
387        context.sendBroadcast(intent);
388    }
389
390    protected static String convertToQuotedString(String string) {
391        return "\"" + string + "\"";
392    }
393
394    @Override
395    protected void onDestroy() {
396        super.onDestroy();
397
398        //Unregister receiver
399        if (mConnectivityReceiver != null) {
400            unregisterReceiver(mConnectivityReceiver);
401        }
402        if (mWifiReceiver != null) {
403            unregisterReceiver(mWifiReceiver);
404        }
405        Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
406    }
407}
408