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