1 /* 2 * Copyright (C) 2010, 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.connectivitymanagertest; 18 19 import android.app.KeyguardManager; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.net.ConnectivityManager; 25 import android.net.NetworkInfo; 26 import android.net.NetworkInfo.State; 27 import android.net.wifi.ScanResult; 28 import android.net.wifi.WifiConfiguration; 29 import android.net.wifi.WifiManager; 30 import android.os.PowerManager; 31 import android.os.SystemClock; 32 import android.test.InstrumentationTestCase; 33 import android.util.Log; 34 import android.view.KeyEvent; 35 36 import java.io.IOException; 37 import java.net.UnknownHostException; 38 import java.util.List; 39 40 41 /** 42 * Base InstrumentationTestCase for Connectivity Manager (CM) test suite 43 * 44 * It registers connectivity manager broadcast and WiFi broadcast to provide 45 * network connectivity information, also provides a set of utility functions 46 * to modify and verify connectivity states. 47 * 48 * A CM test case should extend this base class. 49 */ 50 public class ConnectivityManagerTestBase extends InstrumentationTestCase { 51 52 private static final String[] PING_HOST_LIST = { 53 "www.google.com", "www.yahoo.com", "www.bing.com", "www.facebook.com", "www.ask.com"}; 54 55 protected static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds 56 protected static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds 57 protected static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds 58 protected static final long LONG_TIMEOUT = 2 * 60 * 1000; // 2 minutes 59 protected static final long WIFI_CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 minutes 60 // 2 minutes timer between wifi stop and start 61 protected static final long WIFI_STOP_START_INTERVAL = 2 * 60 * 1000; // 2 minutes 62 // Set ping test timer to be 3 minutes 63 protected static final long PING_TIMER = 3 * 60 *1000; // 3 minutes 64 protected static final int SUCCESS = 0; // for Wifi tethering state change 65 protected static final int FAILURE = 1; 66 protected static final int INIT = -1; 67 68 protected final String mLogTag; 69 70 private ConnectivityReceiver mConnectivityReceiver = null; 71 private WifiReceiver mWifiReceiver = null; 72 73 private long mLastConnectivityChangeTime = -1; 74 protected ConnectivityManager mCm; 75 private Context mContext; 76 protected List<ScanResult> mLastScanResult; 77 protected Object mWifiScanResultLock = new Object(); 78 79 /* Control Wifi States */ 80 public WifiManager mWifiManager; 81 82 public ConnectivityManagerTestBase(String logTag) { 83 super(); 84 mLogTag = logTag; 85 } 86 87 protected long getLastConnectivityChangeTime() { 88 return mLastConnectivityChangeTime; 89 } 90 91 /** 92 * A wrapper of a broadcast receiver which provides network connectivity information 93 * for all kinds of network: wifi, mobile, etc. 94 */ 95 private class ConnectivityReceiver extends BroadcastReceiver { 96 @Override 97 public void onReceive(Context context, Intent intent) { 98 mLastConnectivityChangeTime = SystemClock.uptimeMillis(); 99 logv("ConnectivityReceiver: " + intent); 100 String action = intent.getAction(); 101 if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 102 Log.v("ConnectivityReceiver", "onReceive() called with " + intent); 103 } 104 } 105 } 106 107 private class WifiReceiver extends BroadcastReceiver { 108 @Override 109 public void onReceive(Context context, Intent intent) { 110 String action = intent.getAction(); 111 Log.v("WifiReceiver", "onReceive() is calleld with " + intent); 112 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 113 logv("scan results are available"); 114 synchronized (mWifiScanResultLock) { 115 mLastScanResult = mWifiManager.getScanResults(); 116 mWifiScanResultLock.notifyAll(); 117 } 118 } 119 } 120 } 121 122 @Override 123 protected void setUp() throws Exception { 124 mLastScanResult = null; 125 mContext = getInstrumentation().getContext(); 126 127 // Get an instance of ConnectivityManager 128 mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 129 // Get an instance of WifiManager 130 mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE); 131 132 if (mWifiManager.isWifiApEnabled()) { 133 // if soft AP is enabled, disable it 134 mWifiManager.setWifiApEnabled(null, false); 135 logv("Disable soft ap"); 136 } 137 138 // register a connectivity receiver for CONNECTIVITY_ACTION; 139 mConnectivityReceiver = new ConnectivityReceiver(); 140 mContext.registerReceiver(mConnectivityReceiver, 141 new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 142 143 mWifiReceiver = new WifiReceiver(); 144 IntentFilter mIntentFilter = new IntentFilter(); 145 mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 146 mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 147 mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 148 mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 149 mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 150 mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); 151 mContext.registerReceiver(mWifiReceiver, mIntentFilter); 152 153 logv("Clear Wifi before we start the test."); 154 removeConfiguredNetworksAndDisableWifi(); 155 } 156 157 // wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, 158 // DISCONNECTED, UNKNOWN 159 protected boolean waitForNetworkState(int networkType, State expectedState, long timeout) { 160 long startTime = SystemClock.uptimeMillis(); 161 while (true) { 162 NetworkInfo ni = mCm.getNetworkInfo(networkType); 163 if (ni != null && expectedState.equals(ni.getState())) { 164 logv("waitForNetworkState success: %s", ni); 165 return true; 166 } 167 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 168 logv("waitForNetworkState timeout: %s", ni); 169 return false; 170 } 171 logv("waitForNetworkState interim: %s", ni); 172 SystemClock.sleep(SHORT_TIMEOUT); 173 } 174 } 175 176 // wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED, 177 // WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN 178 protected boolean waitForWifiState(int expectedState, long timeout) { 179 long startTime = SystemClock.uptimeMillis(); 180 while (true) { 181 int state = mWifiManager.getWifiState(); 182 if (state == expectedState) { 183 logv("waitForWifiState success: state=" + state); 184 return true; 185 } 186 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 187 logv("waitForWifiState timeout: expected=%d, actual=%d", expectedState, state); 188 return false; 189 } 190 logv("waitForWifiState interim: expected=%d, actual=%d", expectedState, state); 191 SystemClock.sleep(SHORT_TIMEOUT); 192 } 193 } 194 195 // Wait for Wifi AP state: WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING, 196 // WIFI_AP_STATE_ENABLED, WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN 197 protected boolean waitForWifiApState(int expectedState, long timeout) { 198 long startTime = SystemClock.uptimeMillis(); 199 while (true) { 200 int state = mWifiManager.getWifiApState(); 201 if (state == expectedState) { 202 logv("waitForWifiAPState success: state=" + state); 203 return true; 204 } 205 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 206 logv(String.format("waitForWifiAPState timeout: expected=%d, actual=%d", 207 expectedState, state)); 208 return false; 209 } 210 logv(String.format("waitForWifiAPState interim: expected=%d, actual=%d", 211 expectedState, state)); 212 SystemClock.sleep(SHORT_TIMEOUT); 213 } 214 } 215 216 /** 217 * Wait for the wifi tethering result: 218 * @param timeout is the maximum waiting time 219 * @return SUCCESS if tethering result is successful 220 * FAILURE if tethering result returns error. 221 */ 222 protected boolean waitForTetherStateChange(long timeout) { 223 long startTime = SystemClock.uptimeMillis(); 224 String[] wifiRegexes = mCm.getTetherableWifiRegexs(); 225 while (true) { 226 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 227 return false; 228 } 229 String[] active = mCm.getTetheredIfaces(); 230 String[] error = mCm.getTetheringErroredIfaces(); 231 for (String iface: active) { 232 for (String regex: wifiRegexes) { 233 if (iface.matches(regex)) { 234 return true; 235 } 236 } 237 } 238 for (String iface: error) { 239 for (String regex: wifiRegexes) { 240 if (iface.matches(regex)) { 241 return false; 242 } 243 } 244 } 245 SystemClock.sleep(SHORT_TIMEOUT); 246 } 247 } 248 249 // Return true if device is currently connected to mobile network 250 protected boolean isConnectedToMobile() { 251 return (mCm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_MOBILE); 252 } 253 254 // Return true if device is currently connected to Wifi 255 protected boolean isConnectedToWifi() { 256 return (mCm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI); 257 } 258 259 protected boolean enableWifi() { 260 return mWifiManager.setWifiEnabled(true); 261 } 262 263 // Turn screen off 264 protected void turnScreenOff() { 265 logv("Turn screen off"); 266 PowerManager pm = 267 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 268 pm.goToSleep(SystemClock.uptimeMillis()); 269 } 270 271 // Turn screen on 272 protected void turnScreenOn() { 273 logv("Turn screen on"); 274 PowerManager pm = 275 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 276 pm.wakeUp(SystemClock.uptimeMillis()); 277 // disable lock screen 278 KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 279 if (km.inKeyguardRestrictedInputMode()) { 280 sendKeys(KeyEvent.KEYCODE_MENU); 281 } 282 } 283 284 /** 285 * @return true if the ping test is successful, false otherwise. 286 */ 287 protected boolean pingTest() { 288 long startTime = System.currentTimeMillis(); 289 while ((System.currentTimeMillis() - startTime) < PING_TIMER) { 290 try { 291 // assume the chance that all servers are down is very small 292 for (String host : PING_HOST_LIST) { 293 logv("Start ping test, ping " + host); 294 Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host); 295 int status = p.waitFor(); 296 if (status == 0) { 297 // if any of the ping test is successful, return true 298 return true; 299 } 300 } 301 } catch (UnknownHostException e) { 302 logv("Ping test Fail: Unknown Host"); 303 } catch (IOException e) { 304 logv("Ping test Fail: IOException"); 305 } catch (InterruptedException e) { 306 logv("Ping test Fail: InterruptedException"); 307 } 308 SystemClock.sleep(SHORT_TIMEOUT); 309 } 310 // ping test timeout 311 return false; 312 } 313 314 /** 315 * Associate the device to given SSID 316 * If the device is already associated with a WiFi, disconnect and forget it, 317 * We don't verify whether the connection is successful or not, leave this to the test 318 */ 319 protected boolean connectToWifi(String ssid, String password) { 320 WifiConfiguration config; 321 if (password == null) { 322 config = WifiConfigurationHelper.createOpenConfig(ssid); 323 } else { 324 config = WifiConfigurationHelper.createPskConfig(ssid, password); 325 } 326 return connectToWifiWithConfiguration(config); 327 } 328 329 /** 330 * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration 331 * is pure string, we need to convert it to quoted string. 332 */ 333 protected boolean connectToWifiWithConfiguration(WifiConfiguration config) { 334 // If Wifi is not enabled, enable it 335 if (!mWifiManager.isWifiEnabled()) { 336 logv("Wifi is not enabled, enable it"); 337 mWifiManager.setWifiEnabled(true); 338 // wait for the wifi state change before start scanning. 339 if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT)) { 340 logv("wait for WIFI_STATE_ENABLED failed"); 341 return false; 342 } 343 } 344 345 // Save network configuration and connect to network without scanning 346 mWifiManager.connect(config, 347 new WifiManager.ActionListener() { 348 @Override 349 public void onSuccess() { 350 } 351 352 @Override 353 public void onFailure(int reason) { 354 logv("connect failure " + reason); 355 } 356 }); 357 return true; 358 } 359 360 /* 361 * Disconnect from the current AP and remove configured networks. 362 */ 363 protected boolean disconnectAP() { 364 // remove saved networks 365 if (!mWifiManager.isWifiEnabled()) { 366 logv("Enabled wifi before remove configured networks"); 367 mWifiManager.setWifiEnabled(true); 368 SystemClock.sleep(SHORT_TIMEOUT); 369 } 370 371 List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks(); 372 if (wifiConfigList == null) { 373 logv("no configuration list is null"); 374 return true; 375 } 376 logv("size of wifiConfigList: " + wifiConfigList.size()); 377 for (WifiConfiguration wifiConfig: wifiConfigList) { 378 logv("remove wifi configuration: " + wifiConfig.networkId); 379 int netId = wifiConfig.networkId; 380 mWifiManager.forget(netId, new WifiManager.ActionListener() { 381 @Override 382 public void onSuccess() { 383 } 384 385 @Override 386 public void onFailure(int reason) { 387 logv("Failed to forget " + reason); 388 } 389 }); 390 } 391 return true; 392 } 393 /** 394 * Disable Wifi 395 * @return true if Wifi is disabled successfully 396 */ 397 protected boolean disableWifi() { 398 return mWifiManager.setWifiEnabled(false); 399 } 400 401 /** 402 * Remove configured networks and disable wifi 403 */ 404 protected boolean removeConfiguredNetworksAndDisableWifi() { 405 if (!disconnectAP()) { 406 return false; 407 } 408 SystemClock.sleep(SHORT_TIMEOUT); 409 if (!mWifiManager.setWifiEnabled(false)) { 410 return false; 411 } 412 SystemClock.sleep(SHORT_TIMEOUT); 413 return true; 414 } 415 416 protected static String convertToQuotedString(String string) { 417 return "\"" + string + "\""; 418 } 419 420 protected boolean waitForActiveNetworkConnection(long timeout) { 421 long startTime = SystemClock.uptimeMillis(); 422 while (true) { 423 NetworkInfo ni = mCm.getActiveNetworkInfo(); 424 if (ni != null && ni.isConnected()) { 425 return true; 426 } 427 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 428 logv("waitForActiveNetworkConnection timeout: %s", ni); 429 return false; 430 } 431 logv("waitForActiveNetworkConnection interim: %s", ni); 432 SystemClock.sleep(SHORT_TIMEOUT); 433 } 434 } 435 436 protected boolean waitUntilNoActiveNetworkConnection(long timeout) { 437 long startTime = SystemClock.uptimeMillis(); 438 while (true) { 439 NetworkInfo ni = mCm.getActiveNetworkInfo(); 440 if (ni == null) { 441 return true; 442 } 443 if ((SystemClock.uptimeMillis() - startTime) > timeout) { 444 logv("waitForActiveNetworkConnection timeout: %s", ni); 445 return false; 446 } 447 logv("waitForActiveNetworkConnection interim: %s", ni); 448 SystemClock.sleep(SHORT_TIMEOUT); 449 } 450 } 451 452 // use ping request against Google public DNS to verify connectivity 453 protected boolean checkNetworkConnectivity() { 454 assertTrue("no active network connection", waitForActiveNetworkConnection(LONG_TIMEOUT)); 455 return pingTest(); 456 } 457 458 @Override 459 protected void tearDown() throws Exception{ 460 //Unregister receiver 461 if (mConnectivityReceiver != null) { 462 mContext.unregisterReceiver(mConnectivityReceiver); 463 } 464 if (mWifiReceiver != null) { 465 mContext.unregisterReceiver(mWifiReceiver); 466 } 467 super.tearDown(); 468 } 469 470 protected void logv(String format, Object... args) { 471 Log.v(mLogTag, String.format(format, args)); 472 } 473 474 /** 475 * Connect to the provided Wi-Fi network 476 * @param config is the network configuration 477 * @throws AssertionError if fails to associate and connect to wifi ap 478 */ 479 protected void connectToWifi(WifiConfiguration config) { 480 // step 1: connect to the test access point 481 assertTrue("failed to associate with " + config.SSID, 482 connectToWifiWithConfiguration(config)); 483 484 // step 2: verify Wifi state and network state; 485 assertTrue("wifi state not connected with " + config.SSID, 486 waitForNetworkState(ConnectivityManager.TYPE_WIFI, 487 State.CONNECTED, WIFI_CONNECTION_TIMEOUT)); 488 489 // step 3: verify the current connected network is the given SSID 490 assertNotNull("no active wifi info", mWifiManager.getConnectionInfo()); 491 assertEquals("SSID mismatch", config.SSID, mWifiManager.getConnectionInfo().getSSID()); 492 } 493 } 494