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