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