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