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 com.android.connectivitymanagertest.R; 20 import android.app.Activity; 21 import android.content.Context; 22 import android.content.res.Resources; 23 import android.content.BroadcastReceiver; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.os.Bundle; 27 import android.provider.Settings; 28 import android.util.Log; 29 import android.view.KeyEvent; 30 31 import java.io.InputStream; 32 import java.util.ArrayList; 33 import java.util.List; 34 import android.widget.LinearLayout; 35 import android.net.ConnectivityManager; 36 import android.net.NetworkInfo; 37 import android.net.NetworkInfo.State; 38 39 import android.net.wifi.SupplicantState; 40 import android.net.wifi.WifiConfiguration; 41 import android.net.wifi.WifiManager; 42 import android.net.wifi.WifiInfo; 43 import android.net.wifi.ScanResult; 44 import android.net.wifi.WifiConfiguration.KeyMgmt; 45 46 /** 47 * An activity registered with connectivity manager broadcast 48 * provides network connectivity information and 49 * can be used to set device states: Cellular, Wifi, Airplane mode. 50 */ 51 public class ConnectivityManagerTestActivity extends Activity { 52 53 public static final String LOG_TAG = "ConnectivityManagerTestActivity"; 54 public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds 55 public static final int WIFI_SCAN_TIMEOUT = 20 * 1000; 56 public static final int SHORT_TIMEOUT = 5 * 1000; 57 public static final long LONG_TIMEOUT = 50 * 1000; 58 private static final String ACCESS_POINT_FILE = "accesspoints.xml"; 59 public ConnectivityReceiver mConnectivityReceiver = null; 60 public WifiReceiver mWifiReceiver = null; 61 /* 62 * Track network connectivity information 63 */ 64 public State mState; 65 public NetworkInfo mNetworkInfo; 66 public NetworkInfo mOtherNetworkInfo; 67 public boolean mIsFailOver; 68 public String mReason; 69 public boolean mScanResultIsAvailable = false; 70 public ConnectivityManager mCM; 71 public Object wifiObject = new Object(); 72 public Object connectivityObject = new Object(); 73 public int mWifiState; 74 public NetworkInfo mWifiNetworkInfo; 75 public String mBssid; 76 public String mPowerSsid = "GoogleGuest"; //Default power SSID 77 private Context mContext; 78 79 /* 80 * Control Wifi States 81 */ 82 public WifiManager mWifiManager; 83 84 /* 85 * Verify connectivity state 86 */ 87 public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1; 88 NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES]; 89 90 /** 91 * A wrapper of a broadcast receiver which provides network connectivity information 92 * for all kinds of network: wifi, mobile, etc. 93 */ 94 private class ConnectivityReceiver extends BroadcastReceiver { 95 @Override 96 public void onReceive(Context context, Intent intent) { 97 Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent); 98 String action = intent.getAction(); 99 if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 100 Log.v("ConnectivityReceiver", "onReceive() called with " + intent); 101 return; 102 } 103 104 boolean noConnectivity = 105 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 106 107 if (noConnectivity) { 108 mState = State.DISCONNECTED; 109 } else { 110 mState = State.CONNECTED; 111 } 112 113 mNetworkInfo = (NetworkInfo) 114 intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); 115 116 mOtherNetworkInfo = (NetworkInfo) 117 intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO); 118 119 mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON); 120 mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false); 121 122 Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString()); 123 if (mOtherNetworkInfo != null) { 124 Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString()); 125 } 126 recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState()); 127 if (mOtherNetworkInfo != null) { 128 recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState()); 129 } 130 notifyNetworkConnectivityChange(); 131 } 132 } 133 134 private class WifiReceiver extends BroadcastReceiver { 135 @Override 136 public void onReceive(Context context, Intent intent) { 137 String action = intent.getAction(); 138 Log.v("WifiReceiver", "onReceive() is calleld with " + intent); 139 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 140 notifyScanResult(); 141 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 142 mWifiNetworkInfo = 143 (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 144 Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString()); 145 if (mWifiNetworkInfo.getState() == State.CONNECTED) { 146 mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID); 147 } 148 notifyWifiState(); 149 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 150 mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 151 WifiManager.WIFI_STATE_UNKNOWN); 152 notifyWifiState(); 153 } 154 else { 155 return; 156 } 157 } 158 } 159 160 public ConnectivityManagerTestActivity() { 161 mState = State.UNKNOWN; 162 } 163 164 @Override 165 protected void onCreate(Bundle savedInstanceState) { 166 super.onCreate(savedInstanceState); 167 Log.v(LOG_TAG, "onCreate, inst=" + Integer.toHexString(hashCode())); 168 169 // Create a simple layout 170 LinearLayout contentView = new LinearLayout(this); 171 contentView.setOrientation(LinearLayout.VERTICAL); 172 setContentView(contentView); 173 setTitle("ConnectivityManagerTestActivity"); 174 175 176 // register a connectivity receiver for CONNECTIVITY_ACTION; 177 mConnectivityReceiver = new ConnectivityReceiver(); 178 registerReceiver(mConnectivityReceiver, 179 new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 180 181 mWifiReceiver = new WifiReceiver(); 182 IntentFilter mIntentFilter = new IntentFilter(); 183 mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 184 mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 185 mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 186 mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 187 registerReceiver(mWifiReceiver, mIntentFilter); 188 189 // Get an instance of ConnectivityManager 190 mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); 191 // Get an instance of WifiManager 192 mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE); 193 initializeNetworkStates(); 194 195 if (mWifiManager.isWifiEnabled()) { 196 Log.v(LOG_TAG, "Clear Wifi before we start the test."); 197 removeConfiguredNetworksAndDisableWifi(); 198 } 199 } 200 201 public List<WifiConfiguration> loadNetworkConfigurations() throws Exception { 202 InputStream in = getAssets().open(ACCESS_POINT_FILE); 203 AccessPointParserHelper parseHelper = new AccessPointParserHelper(); 204 return parseHelper.processAccessPoint(in); 205 } 206 207 private void printNetConfig(String[] configuration) { 208 for (int i = 0; i < configuration.length; i++) { 209 if (i == 0) { 210 Log.v(LOG_TAG, "SSID: " + configuration[0]); 211 } else { 212 Log.v(LOG_TAG, " " + configuration[i]); 213 } 214 } 215 } 216 217 // for each network type, initialize network states to UNKNOWN, and no verification flag is set 218 public void initializeNetworkStates() { 219 for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) { 220 connectivityState[networkType] = new NetworkState(); 221 Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " + 222 connectivityState[networkType].toString()); 223 } 224 } 225 226 // deposit a network state 227 public void recordNetworkState(int networkType, State networkState) { 228 Log.v(LOG_TAG, "record network state for network " + networkType + 229 ", state is " + networkState); 230 connectivityState[networkType].recordState(networkState); 231 } 232 233 // set the state transition criteria 234 public void setStateTransitionCriteria(int networkType, State initState, 235 int transitionDir, State targetState) { 236 connectivityState[networkType].setStateTransitionCriteria( 237 initState, transitionDir, targetState); 238 } 239 240 // Validate the states recorded 241 public boolean validateNetworkStates(int networkType) { 242 Log.v(LOG_TAG, "validate network state for " + networkType + ": "); 243 return connectivityState[networkType].validateStateTransition(); 244 } 245 246 // return result from network state validation 247 public String getTransitionFailureReason(int networkType) { 248 Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " + 249 connectivityState[networkType].toString()); 250 return connectivityState[networkType].getReason(); 251 } 252 253 private void notifyNetworkConnectivityChange() { 254 synchronized(connectivityObject) { 255 Log.v(LOG_TAG, "notify network connectivity changed"); 256 connectivityObject.notifyAll(); 257 } 258 } 259 private void notifyScanResult() { 260 synchronized (this) { 261 Log.v(LOG_TAG, "notify that scan results are available"); 262 this.notify(); 263 } 264 } 265 266 public void notifyWifiState() { 267 synchronized (wifiObject) { 268 Log.v(LOG_TAG, "notify wifi state changed"); 269 wifiObject.notify(); 270 } 271 } 272 273 // Wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, 274 // DISCONNECTING, DISCONNECTED, UNKNOWN 275 public boolean waitForNetworkState(int networkType, State expectedState, long timeout) { 276 long startTime = System.currentTimeMillis(); 277 while (true) { 278 if ((System.currentTimeMillis() - startTime) > timeout) { 279 if (mCM.getNetworkInfo(networkType).getState() != expectedState) { 280 return false; 281 } else { 282 // the broadcast has been sent out. the state has been changed. 283 Log.v(LOG_TAG, "networktype: " + networkType + " state: " + 284 mCM.getNetworkInfo(networkType)); 285 return true; 286 } 287 } 288 Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType + 289 " to be " + expectedState.toString()); 290 synchronized (connectivityObject) { 291 try { 292 connectivityObject.wait(SHORT_TIMEOUT); 293 } catch (InterruptedException e) { 294 e.printStackTrace(); 295 } 296 if ((mNetworkInfo.getType() != networkType) || 297 (mNetworkInfo.getState() != expectedState)) { 298 Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() + 299 "is: " + mNetworkInfo.getState()); 300 continue; 301 } 302 return true; 303 } 304 } 305 } 306 307 // Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED, 308 // WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN 309 public boolean waitForWifiState(int expectedState, long timeout) { 310 long startTime = System.currentTimeMillis(); 311 while (true) { 312 if ((System.currentTimeMillis() - startTime) > timeout) { 313 if (mWifiState != expectedState) { 314 return false; 315 } else { 316 return true; 317 } 318 } 319 Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState); 320 synchronized (wifiObject) { 321 try { 322 wifiObject.wait(SHORT_TIMEOUT); 323 } catch (InterruptedException e) { 324 e.printStackTrace(); 325 } 326 if (mWifiState != expectedState) { 327 Log.v(LOG_TAG, "Wifi state is: " + mWifiNetworkInfo.getState()); 328 continue; 329 } 330 return true; 331 } 332 } 333 } 334 335 // Return true if device is currently connected to mobile network 336 public boolean isConnectedToMobile() { 337 return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE); 338 } 339 340 // Return true if device is currently connected to Wifi 341 public boolean isConnectedToWifi() { 342 return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI); 343 } 344 345 public boolean enableWifi() { 346 return mWifiManager.setWifiEnabled(true); 347 } 348 349 /** 350 * Associate the device to given SSID 351 * If the device is already associated with a WiFi, disconnect and forget it, 352 * We don't verify whether the connection is successful or not, leave this to the test 353 */ 354 public boolean connectToWifi(String knownSSID) { 355 WifiConfiguration config = new WifiConfiguration(); 356 config.SSID = knownSSID; 357 config.allowedKeyManagement.set(KeyMgmt.NONE); 358 return connectToWifiWithConfiguration(config); 359 } 360 361 /** 362 * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration 363 * is pure string, we need to convert it to quoted string. 364 * @param config 365 * @return 366 */ 367 public boolean connectToWifiWithConfiguration(WifiConfiguration config) { 368 String ssid = config.SSID; 369 config.SSID = convertToQuotedString(ssid); 370 371 //If Wifi is not enabled, enable it 372 if (!mWifiManager.isWifiEnabled()) { 373 Log.v(LOG_TAG, "Wifi is not enabled, enable it"); 374 mWifiManager.setWifiEnabled(true); 375 } 376 377 List<ScanResult> netList = mWifiManager.getScanResults(); 378 if (netList == null) { 379 Log.v(LOG_TAG, "scan results are null"); 380 // if no scan results are available, start active scan 381 mWifiManager.startScanActive(); 382 mScanResultIsAvailable = false; 383 long startTime = System.currentTimeMillis(); 384 while (!mScanResultIsAvailable) { 385 if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) { 386 return false; 387 } 388 // wait for the scan results to be available 389 synchronized (this) { 390 // wait for the scan result to be available 391 try { 392 this.wait(WAIT_FOR_SCAN_RESULT); 393 } catch (InterruptedException e) { 394 e.printStackTrace(); 395 } 396 if ((mWifiManager.getScanResults() == null) || 397 (mWifiManager.getScanResults().size() <= 0)) { 398 continue; 399 } 400 mScanResultIsAvailable = true; 401 } 402 } 403 } 404 405 netList = mWifiManager.getScanResults(); 406 407 for (int i = 0; i < netList.size(); i++) { 408 ScanResult sr= netList.get(i); 409 if (sr.SSID.equals(ssid)) { 410 Log.v(LOG_TAG, "found " + ssid + " in the scan result list"); 411 int networkId = mWifiManager.addNetwork(config); 412 // Connect to network by disabling others. 413 mWifiManager.enableNetwork(networkId, true); 414 mWifiManager.saveConfiguration(); 415 List<WifiConfiguration> wifiNetworks = mWifiManager.getConfiguredNetworks(); 416 for (WifiConfiguration netConfig : wifiNetworks) { 417 Log.v(LOG_TAG, netConfig.toString()); 418 } 419 420 mWifiManager.reconnect(); 421 break; 422 } 423 } 424 425 List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks(); 426 if (netConfList.size() <= 0) { 427 Log.v(LOG_TAG, ssid + " is not available"); 428 return false; 429 } 430 return true; 431 } 432 433 /* 434 * Disconnect from the current AP and remove configured networks. 435 */ 436 public boolean disconnectAP() { 437 if (mWifiManager.isWifiEnabled()) { 438 //remove the current network Id 439 WifiInfo curWifi = mWifiManager.getConnectionInfo(); 440 if (curWifi == null) { 441 return false; 442 } 443 int curNetworkId = curWifi.getNetworkId(); 444 mWifiManager.removeNetwork(curNetworkId); 445 mWifiManager.saveConfiguration(); 446 447 // remove other saved networks 448 List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks(); 449 if (netConfList != null) { 450 Log.v(LOG_TAG, "remove configured network ids"); 451 for (int i = 0; i < netConfList.size(); i++) { 452 WifiConfiguration conf = new WifiConfiguration(); 453 conf = netConfList.get(i); 454 mWifiManager.removeNetwork(conf.networkId); 455 } 456 } 457 } 458 mWifiManager.saveConfiguration(); 459 return true; 460 } 461 /** 462 * Disable Wifi 463 * @return true if Wifi is disabled successfully 464 */ 465 public boolean disableWifi() { 466 return mWifiManager.setWifiEnabled(false); 467 } 468 469 /** 470 * Remove configured networks and disable wifi 471 */ 472 public boolean removeConfiguredNetworksAndDisableWifi() { 473 if (!disconnectAP()) { 474 return false; 475 } 476 // Disable Wifi 477 if (!mWifiManager.setWifiEnabled(false)) { 478 return false; 479 } 480 // Wait for the actions to be completed 481 try { 482 Thread.sleep(5*1000); 483 } catch (InterruptedException e) {} 484 return true; 485 } 486 487 /** 488 * Set airplane mode 489 */ 490 public void setAirplaneMode(Context context, boolean enableAM) { 491 //set the airplane mode 492 Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 493 enableAM ? 1 : 0); 494 // Post the intent 495 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); 496 intent.putExtra("state", enableAM); 497 context.sendBroadcast(intent); 498 } 499 500 protected static String convertToQuotedString(String string) { 501 return "\"" + string + "\""; 502 } 503 504 @Override 505 protected void onDestroy() { 506 super.onDestroy(); 507 508 //Unregister receiver 509 if (mConnectivityReceiver != null) { 510 unregisterReceiver(mConnectivityReceiver); 511 } 512 if (mWifiReceiver != null) { 513 unregisterReceiver(mWifiReceiver); 514 } 515 Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode())); 516 } 517 518 @Override 519 public void onStart() { 520 super.onStart(); 521 mContext = this; 522 Bundle bundle = this.getIntent().getExtras(); 523 if (bundle != null){ 524 mPowerSsid = bundle.getString("power_ssid"); 525 } 526 } 527 //A thread to set the device into airplane mode then turn on wifi. 528 Thread setDeviceWifiAndAirplaneThread = new Thread(new Runnable() { 529 public void run() { 530 setAirplaneMode(mContext, true); 531 connectToWifi(mPowerSsid); 532 } 533 }); 534 535 //A thread to set the device into wifi 536 Thread setDeviceInWifiOnlyThread = new Thread(new Runnable() { 537 public void run() { 538 connectToWifi(mPowerSsid); 539 } 540 }); 541 542 @Override 543 public boolean onKeyDown(int keyCode, KeyEvent event) { 544 switch (keyCode) { 545 //This is a tricky way for the scripted monkey to 546 //set the device in wifi and wifi in airplane mode. 547 case KeyEvent.KEYCODE_1: 548 setDeviceWifiAndAirplaneThread.start(); 549 break; 550 551 case KeyEvent.KEYCODE_2: 552 setDeviceInWifiOnlyThread.start(); 553 break; 554 } 555 return super.onKeyDown(keyCode, event); 556 } 557 } 558