1/*
2 * Copyright (C) 2011, 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.bandwidthtest.util;
18
19import android.app.DownloadManager;
20import android.app.DownloadManager.Query;
21import android.app.DownloadManager.Request;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.ApplicationInfo;
27import android.content.pm.PackageManager;
28import android.content.pm.PackageManager.NameNotFoundException;
29import android.database.Cursor;
30import android.net.ConnectivityManager;
31import android.net.NetworkInfo;
32import android.net.NetworkInfo.State;
33import android.net.Uri;
34import android.net.wifi.ScanResult;
35import android.net.wifi.WifiConfiguration;
36import android.net.wifi.WifiConfiguration.KeyMgmt;
37import android.net.wifi.WifiManager;
38import android.os.Handler;
39import android.os.Message;
40import android.provider.Settings;
41import android.util.Log;
42
43import com.android.bandwidthtest.NetworkState;
44import com.android.bandwidthtest.NetworkState.StateTransitionDirection;
45import com.android.internal.util.AsyncChannel;
46
47import junit.framework.Assert;
48
49import java.io.IOException;
50import java.net.UnknownHostException;
51import java.util.List;
52
53/*
54 * Utility class used to set the connectivity of the device and to download files.
55 */
56public class ConnectionUtil {
57    private static final String LOG_TAG = "ConnectionUtil";
58    private static final String DOWNLOAD_MANAGER_PKG_NAME = "com.android.providers.downloads";
59    private static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; // 10 seconds
60    private static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
61    public static final int SHORT_TIMEOUT = 5 * 1000;
62    public static final int LONG_TIMEOUT = 5 * 60 * 1000; // 5 minutes
63    private ConnectivityReceiver mConnectivityReceiver = null;
64    private WifiReceiver mWifiReceiver = null;
65    private DownloadReceiver mDownloadReceiver = null;
66    private DownloadManager mDownloadManager;
67    private NetworkInfo mNetworkInfo;
68    private NetworkInfo mOtherNetworkInfo;
69    private boolean mScanResultIsAvailable = false;
70    private ConnectivityManager mCM;
71    private Object mWifiMonitor = new Object();
72    private Object mConnectivityMonitor = new Object();
73    private Object mDownloadMonitor = new Object();
74    private int mWifiState;
75    private NetworkInfo mWifiNetworkInfo;
76    private WifiManager mWifiManager;
77    private WifiManager.Channel mChannel;
78    private Context mContext;
79    // Verify connectivity state
80    private static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
81    private NetworkState[] mConnectivityState = new NetworkState[NUM_NETWORK_TYPES];
82
83    public ConnectionUtil(Context context) {
84        mContext = context;
85    }
86
87    /**
88     * Initialize the class. Needs to be called before any other methods in {@link ConnectionUtil}
89     *
90     * @throws Exception
91     */
92    public void initialize() throws Exception {
93        // Register a connectivity receiver for CONNECTIVITY_ACTION
94        mConnectivityReceiver = new ConnectivityReceiver();
95        mContext.registerReceiver(mConnectivityReceiver,
96                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
97
98        // Register a download receiver for ACTION_DOWNLOAD_COMPLETE
99        mDownloadReceiver = new DownloadReceiver();
100        mContext.registerReceiver(mDownloadReceiver,
101                new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
102
103        // Register a wifi receiver
104        mWifiReceiver = new WifiReceiver();
105        IntentFilter mIntentFilter = new IntentFilter();
106        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
107        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
108        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
109        mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
110        mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
111        mContext.registerReceiver(mWifiReceiver, mIntentFilter);
112
113        // Get an instance of ConnectivityManager
114        mCM = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
115
116        // Get an instance of WifiManager
117        mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
118        mChannel = mWifiManager.initialize(mContext, mContext.getMainLooper(), null);
119
120        mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE);
121
122        initializeNetworkStates();
123
124
125    }
126
127    /**
128     * Additional initialization needed for wifi related tests.
129     */
130    public void wifiTestInit() {
131        mWifiManager.setWifiEnabled(true);
132        Log.v(LOG_TAG, "Clear Wifi before we start the test.");
133        sleep(SHORT_TIMEOUT);
134        removeConfiguredNetworksAndDisableWifi();
135    }
136
137
138    /**
139     * A wrapper of a broadcast receiver which provides network connectivity information
140     * for all kinds of network: wifi, mobile, etc.
141     */
142    private class ConnectivityReceiver extends BroadcastReceiver {
143        /**
144         * {@inheritDoc}
145         */
146        @Override
147        public void onReceive(Context context, Intent intent) {
148            if (isInitialStickyBroadcast()) {
149                Log.d(LOG_TAG, "This is a sticky broadcast don't do anything.");
150                return;
151            }
152            Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent);
153            String action = intent.getAction();
154            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
155                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
156                return;
157            }
158
159            final ConnectivityManager connManager = (ConnectivityManager) context
160                    .getSystemService(Context.CONNECTIVITY_SERVICE);
161            mNetworkInfo = connManager.getActiveNetworkInfo();
162
163            if (intent.hasExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO)) {
164                mOtherNetworkInfo = (NetworkInfo)
165                        intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
166            }
167
168            Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString());
169            recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
170            if (mOtherNetworkInfo != null) {
171                Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
172                recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
173            }
174            notifyNetworkConnectivityChange();
175        }
176    }
177
178    /**
179     * A wrapper of a broadcast receiver which provides wifi information.
180     */
181    private class WifiReceiver extends BroadcastReceiver {
182        /**
183         * {@inheritDoc}
184         */
185        @Override
186        public void onReceive(Context context, Intent intent) {
187            String action = intent.getAction();
188            Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
189            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
190                Log.v(LOG_TAG, "Scan results are available");
191                notifyScanResult();
192            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
193                mWifiNetworkInfo =
194                        (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
195                Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
196                if (mWifiNetworkInfo.getState() == State.CONNECTED) {
197                    intent.getStringExtra(WifiManager.EXTRA_BSSID);
198                }
199                notifyWifiState();
200            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
201                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
202                        WifiManager.WIFI_STATE_UNKNOWN);
203                notifyWifiState();
204            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
205                notifyWifiAPState();
206            } else {
207                return;
208            }
209        }
210    }
211
212    /**
213     * A wrapper of a broadcast receiver which provides download manager information.
214     */
215    private class DownloadReceiver extends BroadcastReceiver {
216        /**
217         * {@inheritDoc}
218         */
219        @Override
220        public void onReceive(Context context, Intent intent) {
221            String action = intent.getAction();
222            Log.v("DownloadReceiver", "onReceive() is called with " + intent);
223            // Download complete
224            if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
225                notifiyDownloadState();
226            }
227        }
228    }
229
230    private class WifiServiceHandler extends Handler {
231        /**
232         * {@inheritDoc}
233         */
234        @Override
235        public void handleMessage(Message msg) {
236            switch (msg.what) {
237                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
238                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
239                        // AsyncChannel in msg.obj
240                    } else {
241                        Log.v(LOG_TAG, "Failed to establish AsyncChannel connection");
242                    }
243                    break;
244                default:
245                    // Ignore
246                    break;
247            }
248        }
249    }
250
251    /**
252     * Initialize all the network states.
253     */
254    public void initializeNetworkStates() {
255        // For each network type, initialize network states to UNKNOWN, and no verification
256        // flag is set.
257        for (int networkType = NUM_NETWORK_TYPES - 1; networkType >= 0; networkType--) {
258            mConnectivityState[networkType] =  new NetworkState();
259            Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " +
260                    mConnectivityState[networkType].toString());
261        }
262    }
263
264    public void recordNetworkState(int networkType, State networkState) {
265        // deposit a network state
266        Log.v(LOG_TAG, "record network state for network " +  networkType +
267                ", state is " + networkState);
268        mConnectivityState[networkType].recordState(networkState);
269    }
270
271    /**
272     * Set the state transition criteria
273     *
274     * @param networkType
275     * @param initState
276     * @param transitionDir
277     * @param targetState
278     */
279    public void setStateTransitionCriteria(int networkType, State initState,
280            StateTransitionDirection transitionDir, State targetState) {
281        mConnectivityState[networkType].setStateTransitionCriteria(
282                initState, transitionDir, targetState);
283    }
284
285    /**
286     * Validate the states recorded.
287     * @param networkType
288     * @return
289     */
290    public boolean validateNetworkStates(int networkType) {
291        Log.v(LOG_TAG, "validate network state for " + networkType + ": ");
292        return mConnectivityState[networkType].validateStateTransition();
293    }
294
295    /**
296     * Fetch the failure reason for the transition.
297     * @param networkType
298     * @return result from network state validation
299     */
300    public String getTransitionFailureReason(int networkType) {
301        Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " +
302                mConnectivityState[networkType].toString());
303        return mConnectivityState[networkType].getFailureReason();
304    }
305
306    /**
307     * Send a notification via the mConnectivityMonitor when the network connectivity changes.
308     */
309    private void notifyNetworkConnectivityChange() {
310        synchronized(mConnectivityMonitor) {
311            Log.v(LOG_TAG, "notify network connectivity changed");
312            mConnectivityMonitor.notifyAll();
313        }
314    }
315
316    /**
317     * Send a notification when a scan for the wifi network is done.
318     */
319    private void notifyScanResult() {
320        synchronized (this) {
321            Log.v(LOG_TAG, "notify that scan results are available");
322            this.notify();
323        }
324    }
325
326    /**
327     * Send a notification via the mWifiMonitor when the wifi state changes.
328     */
329    private void notifyWifiState() {
330        synchronized (mWifiMonitor) {
331            Log.v(LOG_TAG, "notify wifi state changed.");
332            mWifiMonitor.notify();
333        }
334    }
335
336    /**
337     * Send a notification via the mDownloadMonitor when a download is complete.
338     */
339    private void notifiyDownloadState() {
340        synchronized (mDownloadMonitor) {
341            Log.v(LOG_TAG, "notifiy download manager state changed.");
342            mDownloadMonitor.notify();
343        }
344    }
345
346    /**
347     * Send a notification when the wifi ap state changes.
348     */
349    private void notifyWifiAPState() {
350        synchronized (this) {
351            Log.v(LOG_TAG, "notify wifi AP state changed.");
352            this.notify();
353        }
354    }
355
356    /**
357     * Start a download on a given url and wait for completion.
358     *
359     * @param targetUrl the target to download.x
360     * @param timeout to wait for download to finish
361     * @return true if we successfully downloaded the requestedUrl, false otherwise.
362     */
363    public boolean startDownloadAndWait(String targetUrl, long timeout) {
364        if (targetUrl.length() == 0 || targetUrl == null) {
365            Log.v(LOG_TAG, "Empty or Null target url requested to DownloadManager");
366            return true;
367        }
368        Request request = new Request(Uri.parse(targetUrl));
369        long enqueue = mDownloadManager.enqueue(request);
370        Log.v(LOG_TAG, "Sending download request of " + targetUrl + " to DownloadManager");
371        long startTime = System.currentTimeMillis();
372        while (true) {
373            if ((System.currentTimeMillis() - startTime) > timeout) {
374                Log.v(LOG_TAG, "startDownloadAndWait timed out, failed to fetch " + targetUrl +
375                        " within " + timeout);
376                return downloadSuccessful(enqueue);
377            }
378            Log.v(LOG_TAG, "Waiting for the download to finish " + targetUrl);
379            synchronized (mDownloadMonitor) {
380                try {
381                    mDownloadMonitor.wait(SHORT_TIMEOUT);
382                } catch (InterruptedException e) {
383                    e.printStackTrace();
384                }
385                if (!downloadSuccessful(enqueue)) {
386                    continue;
387                }
388                return true;
389            }
390        }
391    }
392
393    /**
394     * Fetch the Download Manager's UID.
395     * @return the Download Manager's UID
396     */
397    public int downloadManagerUid() {
398        try {
399            PackageManager pm = mContext.getPackageManager();
400            ApplicationInfo appInfo = pm.getApplicationInfo(DOWNLOAD_MANAGER_PKG_NAME,
401                    PackageManager.GET_META_DATA);
402            return appInfo.uid;
403        } catch (NameNotFoundException e) {
404            Log.d(LOG_TAG, "Did not find the package for the download service.");
405            return -1;
406        }
407    }
408
409    /**
410     * Determines if a given download was successful by querying the DownloadManager.
411     *
412     * @param enqueue the id used to identify/query the DownloadManager with.
413     * @return true if download was successful, false otherwise.
414     */
415    private boolean downloadSuccessful(long enqueue) {
416        Query query = new Query();
417        query.setFilterById(enqueue);
418        Cursor c = mDownloadManager.query(query);
419        if (c.moveToFirst()) {
420            int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
421            if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
422                Log.v(LOG_TAG, "Successfully downloaded file!");
423                return true;
424            }
425        }
426        return false;
427    }
428
429    /**
430     * Wait for network connectivity state.
431     * @param networkType the network to check for
432     * @param expectedState the desired state
433     * @param timeout in milliseconds
434     * @return true if the network connectivity state matched what was expected
435     */
436    public boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
437        long startTime = System.currentTimeMillis();
438        while (true) {
439            if ((System.currentTimeMillis() - startTime) > timeout) {
440                Log.v(LOG_TAG, "waitForNetworkState time out, the state of network type " + networkType +
441                        " is: " + mCM.getNetworkInfo(networkType).getState());
442                if (mCM.getNetworkInfo(networkType).getState() != expectedState) {
443                    return false;
444                } else {
445                    // the broadcast has been sent out. the state has been changed.
446                    Log.v(LOG_TAG, "networktype: " + networkType + " state: " +
447                            mCM.getNetworkInfo(networkType));
448                    return true;
449                }
450            }
451            Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
452                    " to be " + expectedState.toString());
453            synchronized (mConnectivityMonitor) {
454                try {
455                    mConnectivityMonitor.wait(SHORT_TIMEOUT);
456                } catch (InterruptedException e) {
457                    e.printStackTrace();
458                }
459                if (mNetworkInfo == null) {
460                    Log.v(LOG_TAG, "Do not have networkInfo! Force fetch of network info.");
461                    mNetworkInfo = mCM.getActiveNetworkInfo();
462                }
463                // Still null after force fetch? Maybe the network did not have time to be brought
464                // up yet.
465                if (mNetworkInfo == null) {
466                    Log.v(LOG_TAG, "Failed to force fetch networkInfo. " +
467                            "The network is still not ready. Wait for the next broadcast");
468                    continue;
469                }
470                if ((mNetworkInfo.getType() != networkType) ||
471                        (mNetworkInfo.getState() != expectedState)) {
472                    Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() +
473                            "is: " + mNetworkInfo.getState());
474                    continue;
475                }
476                return true;
477            }
478        }
479    }
480
481    /**
482     * Wait for a given wifi state to occur within a given timeout.
483     * @param expectedState the expected wifi state.
484     * @param timeout for the state to be set in milliseconds.
485     * @return true if the state was achieved within the timeout, false otherwise.
486     */
487    public boolean waitForWifiState(int expectedState, long timeout) {
488        // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
489        //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
490        long startTime = System.currentTimeMillis();
491        while (true) {
492            if ((System.currentTimeMillis() - startTime) > timeout) {
493                if (mWifiState != expectedState) {
494                    return false;
495                } else {
496                    return true;
497                }
498            }
499            Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
500            synchronized (mWifiMonitor) {
501                try {
502                    mWifiMonitor.wait(SHORT_TIMEOUT);
503                } catch (InterruptedException e) {
504                    e.printStackTrace();
505                }
506                if (mWifiState != expectedState) {
507                    Log.v(LOG_TAG, "Wifi state is: " + mWifiState);
508                    continue;
509                }
510                return true;
511            }
512        }
513    }
514
515    /**
516     * Convenience method to determine if we are connected to a mobile network.
517     * @return true if connected to a mobile network, false otherwise.
518     */
519    public boolean isConnectedToMobile() {
520        NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
521        return networkInfo.isConnected();
522    }
523
524    /**
525     * Convenience method to determine if we are connected to wifi.
526     * @return true if connected to wifi, false otherwise.
527     */
528    public boolean isConnectedToWifi() {
529        NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
530        return networkInfo.isConnected();
531    }
532
533    /**
534     * Associate the device to given SSID
535     * If the device is already associated with a WiFi, disconnect and forget it,
536     * We don't verify whether the connection is successful or not, leave this to the test
537     */
538    public boolean connectToWifi(String knownSSID) {
539        WifiConfiguration config = new WifiConfiguration();
540        config.SSID = knownSSID;
541        config.allowedKeyManagement.set(KeyMgmt.NONE);
542        return connectToWifiWithConfiguration(config);
543    }
544
545    /**
546     * Connect to Wi-Fi with the given configuration.
547     * @param config
548     * @return true if we are connected to a given AP.
549     */
550    public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
551        //  The SSID in the configuration is a pure string, need to convert it to a quoted string.
552        String ssid = config.SSID;
553        config.SSID = convertToQuotedString(ssid);
554
555        // If wifi is not enabled, enable it
556        if (!mWifiManager.isWifiEnabled()) {
557            Log.v(LOG_TAG, "Wifi is not enabled, enable it");
558            mWifiManager.setWifiEnabled(true);
559            // wait for the wifi state change before start scanning.
560            if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, 2 * SHORT_TIMEOUT)) {
561                Log.v(LOG_TAG, "Wait for WIFI_STATE_ENABLED failed");
562                return false;
563            }
564        }
565
566        boolean foundApInScanResults = false;
567        for (int retry = 0; retry < 5; retry++) {
568            List<ScanResult> netList = mWifiManager.getScanResults();
569            if (netList != null) {
570                Log.v(LOG_TAG, "size of scan result list: " + netList.size());
571                for (int i = 0; i < netList.size(); i++) {
572                    ScanResult sr= netList.get(i);
573                    if (sr.SSID.equals(ssid)) {
574                        Log.v(LOG_TAG, "Found " + ssid + " in the scan result list.");
575                        Log.v(LOG_TAG, "Retry: " + retry);
576                        foundApInScanResults = true;
577                        mWifiManager.connect(mChannel, config, new WifiManager.ActionListener() {
578                                public void onSuccess() {
579                                }
580                                public void onFailure(int reason) {
581                                    Log.e(LOG_TAG, "connect failed " + reason);
582                                }
583                            });
584
585                        break;
586                    }
587                }
588            }
589            if (foundApInScanResults) {
590                return true;
591            } else {
592                // Start an active scan
593                mWifiManager.startScanActive();
594                mScanResultIsAvailable = false;
595                long startTime = System.currentTimeMillis();
596                while (!mScanResultIsAvailable) {
597                    if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
598                        Log.v(LOG_TAG, "wait for scan results timeout");
599                        return false;
600                    }
601                    // wait for the scan results to be available
602                    synchronized (this) {
603                        // wait for the scan result to be available
604                        try {
605                            this.wait(WAIT_FOR_SCAN_RESULT);
606                        } catch (InterruptedException e) {
607                            e.printStackTrace();
608                        }
609                        if ((mWifiManager.getScanResults() == null) ||
610                                (mWifiManager.getScanResults().size() <= 0)) {
611                            continue;
612                        }
613                        mScanResultIsAvailable = true;
614                    }
615                }
616            }
617        }
618        return false;
619    }
620
621    /*
622     * Disconnect from the current AP and remove configured networks.
623     */
624    public boolean disconnectAP() {
625        // remove saved networks
626        List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
627        Log.v(LOG_TAG, "size of wifiConfigList: " + wifiConfigList.size());
628        for (WifiConfiguration wifiConfig: wifiConfigList) {
629            Log.v(LOG_TAG, "Remove wifi configuration: " + wifiConfig.networkId);
630            int netId = wifiConfig.networkId;
631            mWifiManager.forget(mChannel, netId, new WifiManager.ActionListener() {
632                    public void onSuccess() {
633                    }
634                    public void onFailure(int reason) {
635                        Log.e(LOG_TAG, "forget failed " + reason);
636                    }
637                });
638        }
639        return true;
640    }
641
642    /**
643     * Enable Wifi
644     * @return true if Wifi is enabled successfully
645     */
646    public boolean enableWifi() {
647        return mWifiManager.setWifiEnabled(true);
648    }
649
650    /**
651     * Disable Wifi
652     * @return true if Wifi is disabled successfully
653     */
654    public boolean disableWifi() {
655        return mWifiManager.setWifiEnabled(false);
656    }
657
658    /**
659     * Remove configured networks and disable wifi
660     */
661    public boolean removeConfiguredNetworksAndDisableWifi() {
662        if (!disconnectAP()) {
663            return false;
664        }
665        sleep(SHORT_TIMEOUT);
666        if (!mWifiManager.setWifiEnabled(false)) {
667            return false;
668        }
669        sleep(SHORT_TIMEOUT);
670        return true;
671    }
672
673    /**
674     * Make the current thread sleep.
675     * @param sleeptime the time to sleep in milliseconds
676     */
677    private void sleep(long sleeptime) {
678        try {
679            Thread.sleep(sleeptime);
680        } catch (InterruptedException e) {}
681    }
682
683    /**
684     * Set airplane mode on device, caller is responsible to ensuring correct state.
685     * @param context {@link Context}
686     * @param enableAM to enable or disable airplane mode.
687     */
688    public void setAirplaneMode(Context context, boolean enableAM) {
689        //set the airplane mode
690        Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
691                enableAM ? 1 : 0);
692        // Post the intent
693        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
694        intent.putExtra("state", enableAM);
695        context.sendBroadcast(intent);
696    }
697
698    /**
699     * Add quotes around the string.
700     * @param string to convert
701     * @return string with quotes around it
702     */
703    protected static String convertToQuotedString(String string) {
704        return "\"" + string + "\"";
705    }
706
707    public void cleanUp() {
708        // Unregister receivers if defined.
709        if (mConnectivityReceiver != null) {
710            mContext.unregisterReceiver(mConnectivityReceiver);
711        }
712        if (mWifiReceiver != null) {
713            mContext.unregisterReceiver(mWifiReceiver);
714        }
715        if (mDownloadReceiver != null) {
716            mContext.unregisterReceiver(mDownloadReceiver);
717        }
718        Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
719    }
720
721    /**
722     * Helper method used to test data connectivity by pinging a series of popular sites.
723     * @return true if device has data connectivity, false otherwise.
724     */
725    public boolean hasData() {
726        String[] hostList = {"www.google.com", "www.yahoo.com",
727                "www.bing.com", "www.facebook.com", "www.ask.com"};
728        try {
729            for (int i = 0; i < hostList.length; ++i) {
730                String host = hostList[i];
731                Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
732                int status = p.waitFor();
733                if (status == 0) {
734                    return true;
735                }
736            }
737        } catch (UnknownHostException e) {
738            Log.e(LOG_TAG, "Ping test Failed: Unknown Host");
739        } catch (IOException e) {
740            Log.e(LOG_TAG, "Ping test Failed: IOException");
741        } catch (InterruptedException e) {
742            Log.e(LOG_TAG, "Ping test Failed: InterruptedException");
743        }
744        return false;
745    }
746}
747