Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 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 android.net.wifi.cts;
     18 
     19 
     20 import android.content.BroadcastReceiver;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.IntentFilter;
     24 import android.content.pm.PackageManager;
     25 import android.net.NetworkInfo;
     26 import android.net.wifi.ScanResult;
     27 import android.net.wifi.WifiConfiguration;
     28 import android.net.wifi.WifiConfiguration.Status;
     29 import android.net.wifi.WifiManager;
     30 import android.net.wifi.WifiManager.TxPacketCountListener;
     31 import android.net.wifi.WifiManager.WifiLock;
     32 import android.net.wifi.hotspot2.PasspointConfiguration;
     33 import android.net.wifi.hotspot2.pps.Credential;
     34 import android.net.wifi.hotspot2.pps.HomeSp;
     35 import android.os.SystemClock;
     36 import android.provider.Settings;
     37 import android.test.AndroidTestCase;
     38 import android.util.Log;
     39 
     40 import com.android.compatibility.common.util.WifiConfigCreator;
     41 
     42 import java.net.HttpURLConnection;
     43 import java.net.URL;
     44 import java.security.MessageDigest;
     45 import java.security.cert.X509Certificate;
     46 import java.util.HashSet;
     47 import java.util.List;
     48 import java.util.Set;
     49 import java.util.concurrent.TimeUnit;
     50 import java.util.concurrent.atomic.AtomicInteger;
     51 
     52 public class WifiManagerTest extends AndroidTestCase {
     53     private static class MySync {
     54         int expectedState = STATE_NULL;
     55     }
     56 
     57     private WifiManager mWifiManager;
     58     private WifiLock mWifiLock;
     59     private static MySync mMySync;
     60     private List<ScanResult> mScanResults = null;
     61     private NetworkInfo mNetworkInfo;
     62     private Object mLOHSLock = new Object();
     63 
     64     // Please refer to WifiManager
     65     private static final int MIN_RSSI = -100;
     66     private static final int MAX_RSSI = -55;
     67 
     68     private static final int STATE_NULL = 0;
     69     private static final int STATE_WIFI_CHANGING = 1;
     70     private static final int STATE_WIFI_ENABLED = 2;
     71     private static final int STATE_WIFI_DISABLED = 3;
     72     private static final int STATE_SCANNING = 4;
     73     private static final int STATE_SCAN_DONE = 5;
     74 
     75     private static final String TAG = "WifiManagerTest";
     76     private static final String SSID1 = "\"WifiManagerTest\"";
     77     private static final String SSID2 = "\"WifiManagerTestModified\"";
     78     private static final String PROXY_TEST_SSID = "SomeProxyAp";
     79     private static final String ADD_NETWORK_EXCEPTION_SUBSTR = "addNetwork";
     80     // A full single scan duration is about 6-7 seconds if country code is set
     81     // to US. If country code is set to world mode (00), we would expect a scan
     82     // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here.
     83     private static final int SCAN_TIMEOUT_MSEC = 9000;
     84     private static final int TIMEOUT_MSEC = 6000;
     85     private static final int WAIT_MSEC = 60;
     86     private static final int DURATION = 10000;
     87     private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000;
     88     private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000;
     89     private static final int WIFI_SCAN_TEST_ITERATIONS = 5;
     90 
     91     private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac";
     92 
     93     private IntentFilter mIntentFilter;
     94     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
     95         @Override
     96         public void onReceive(Context context, Intent intent) {
     97             final String action = intent.getAction();
     98             if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
     99 
    100                 synchronized (mMySync) {
    101                     if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) {
    102                         mScanResults = mWifiManager.getScanResults();
    103                     } else {
    104                         mScanResults = null;
    105                     }
    106                     mMySync.expectedState = STATE_SCAN_DONE;
    107                     mMySync.notifyAll();
    108                 }
    109             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
    110                 int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
    111                         WifiManager.WIFI_STATE_UNKNOWN);
    112                 synchronized (mMySync) {
    113                     if (newState == WifiManager.WIFI_STATE_ENABLED) {
    114                         Log.d(TAG, "*** New WiFi state is ENABLED ***");
    115                         mMySync.expectedState = STATE_WIFI_ENABLED;
    116                         mMySync.notifyAll();
    117                     } else if (newState == WifiManager.WIFI_STATE_DISABLED) {
    118                         Log.d(TAG, "*** New WiFi state is DISABLED ***");
    119                         mMySync.expectedState = STATE_WIFI_DISABLED;
    120                         mMySync.notifyAll();
    121                     }
    122                 }
    123             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
    124                 synchronized (mMySync) {
    125                     mNetworkInfo =
    126                             (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    127                     if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED)
    128                         mMySync.notifyAll();
    129                 }
    130             }
    131         }
    132     };
    133 
    134     @Override
    135     protected void setUp() throws Exception {
    136         super.setUp();
    137         if (!WifiFeature.isWifiSupported(getContext())) {
    138             // skip the test if WiFi is not supported
    139             return;
    140         }
    141         mMySync = new MySync();
    142         mIntentFilter = new IntentFilter();
    143         mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    144         mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
    145         mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
    146         mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
    147         mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    148         mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
    149         mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
    150         mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK);
    151 
    152         mContext.registerReceiver(mReceiver, mIntentFilter);
    153         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
    154         assertNotNull(mWifiManager);
    155         mWifiLock = mWifiManager.createWifiLock(TAG);
    156         mWifiLock.acquire();
    157         if (!mWifiManager.isWifiEnabled())
    158             setWifiEnabled(true);
    159         Thread.sleep(DURATION);
    160         assertTrue(mWifiManager.isWifiEnabled());
    161         synchronized (mMySync) {
    162             mMySync.expectedState = STATE_NULL;
    163         }
    164     }
    165 
    166     @Override
    167     protected void tearDown() throws Exception {
    168         if (!WifiFeature.isWifiSupported(getContext())) {
    169             // skip the test if WiFi is not supported
    170             super.tearDown();
    171             return;
    172         }
    173         if (!mWifiManager.isWifiEnabled())
    174             setWifiEnabled(true);
    175         mWifiLock.release();
    176         mContext.unregisterReceiver(mReceiver);
    177         Thread.sleep(DURATION);
    178         super.tearDown();
    179     }
    180 
    181     private void setWifiEnabled(boolean enable) throws Exception {
    182         synchronized (mMySync) {
    183             if (mWifiManager.isWifiEnabled() != enable) {
    184                 // the new state is different, we expect it to change
    185                 mMySync.expectedState = STATE_WIFI_CHANGING;
    186             } else {
    187                 mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
    188             }
    189             // now trigger the change
    190             assertTrue(mWifiManager.setWifiEnabled(enable));
    191             waitForExpectedWifiState(enable);
    192         }
    193     }
    194 
    195     private void waitForExpectedWifiState(boolean enabled) throws InterruptedException {
    196         synchronized (mMySync) {
    197             long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
    198             int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
    199             while (System.currentTimeMillis() < timeout
    200                     && mMySync.expectedState != expected) {
    201                 mMySync.wait(WAIT_MSEC);
    202             }
    203         }
    204     }
    205 
    206     // Get the current scan status from sticky broadcast.
    207     private boolean isScanCurrentlyAvailable() {
    208         boolean isAvailable = false;
    209         IntentFilter intentFilter = new IntentFilter();
    210         intentFilter.addAction(WifiManager.WIFI_SCAN_AVAILABLE);
    211         Intent intent = mContext.registerReceiver(null, intentFilter);
    212         assertNotNull(intent);
    213         if (intent.getAction().equals(WifiManager.WIFI_SCAN_AVAILABLE)) {
    214             int state = intent.getIntExtra(
    215                     WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_UNKNOWN);
    216             if (state == WifiManager.WIFI_STATE_ENABLED) {
    217                 isAvailable = true;
    218             } else if (state == WifiManager.WIFI_STATE_DISABLED) {
    219                 isAvailable = false;
    220             }
    221         }
    222         return isAvailable;
    223     }
    224 
    225     private void startScan() throws Exception {
    226         synchronized (mMySync) {
    227             mMySync.expectedState = STATE_SCANNING;
    228             mScanResults = null;
    229             assertTrue(mWifiManager.startScan());
    230             long timeout = System.currentTimeMillis() + SCAN_TIMEOUT_MSEC;
    231             while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANNING)
    232                 mMySync.wait(WAIT_MSEC);
    233         }
    234     }
    235 
    236     private void connectWifi() throws Exception {
    237         synchronized (mMySync) {
    238             if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) return;
    239             assertTrue(mWifiManager.reconnect());
    240             long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
    241             while (System.currentTimeMillis() < timeout
    242                     && mNetworkInfo.getState() != NetworkInfo.State.CONNECTED)
    243                 mMySync.wait(WAIT_MSEC);
    244             assertTrue(mNetworkInfo.getState() == NetworkInfo.State.CONNECTED);
    245         }
    246     }
    247 
    248     private boolean existSSID(String ssid) {
    249         for (final WifiConfiguration w : mWifiManager.getConfiguredNetworks()) {
    250             if (w.SSID.equals(ssid))
    251                 return true;
    252         }
    253         return false;
    254     }
    255 
    256     private int findConfiguredNetworks(String SSID, List<WifiConfiguration> networks) {
    257         for (final WifiConfiguration w : networks) {
    258             if (w.SSID.equals(SSID))
    259                 return networks.indexOf(w);
    260         }
    261         return -1;
    262     }
    263 
    264     /**
    265      * test point of wifiManager actions:
    266      * 1.reconnect
    267      * 2.reassociate
    268      * 3.disconnect
    269      * 4.createWifiLock
    270      */
    271     public void testWifiManagerActions() throws Exception {
    272         if (!WifiFeature.isWifiSupported(getContext())) {
    273             // skip the test if WiFi is not supported
    274             return;
    275         }
    276         assertTrue(mWifiManager.reconnect());
    277         assertTrue(mWifiManager.reassociate());
    278         assertTrue(mWifiManager.disconnect());
    279         final String TAG = "Test";
    280         assertNotNull(mWifiManager.createWifiLock(TAG));
    281         assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG));
    282     }
    283 
    284     /**
    285      * Test wifi scanning when location scan is turned off.
    286      */
    287     public void testWifiManagerScanWhenWifiOffLocationTurnedOn() throws Exception {
    288         if (!WifiFeature.isWifiSupported(getContext())) {
    289             // skip the test if WiFi is not supported
    290             return;
    291         }
    292         if (!hasLocationFeature()) {
    293             Log.d(TAG, "Skipping test as location is not supported");
    294             return;
    295         }
    296         if (!isLocationEnabled()) {
    297             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
    298                     + " empty when location is disabled!");
    299         }
    300         setWifiEnabled(false);
    301         Thread.sleep(DURATION);
    302         startScan();
    303         if (mWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) {
    304             // Make sure at least one AP is found.
    305             assertNotNull("mScanResult should not be null!", mScanResults);
    306             assertFalse("empty scan results!", mScanResults.isEmpty());
    307         } else {
    308             // Make sure no scan results are available.
    309             assertNull("mScanResult should be null!", mScanResults);
    310         }
    311         final String TAG = "Test";
    312         assertNotNull(mWifiManager.createWifiLock(TAG));
    313         assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG));
    314     }
    315 
    316     /**
    317      * test point of wifiManager properties:
    318      * 1.enable properties
    319      * 2.DhcpInfo properties
    320      * 3.wifi state
    321      * 4.ConnectionInfo
    322      */
    323     public void testWifiManagerProperties() throws Exception {
    324         if (!WifiFeature.isWifiSupported(getContext())) {
    325             // skip the test if WiFi is not supported
    326             return;
    327         }
    328         setWifiEnabled(true);
    329         assertTrue(mWifiManager.isWifiEnabled());
    330         assertNotNull(mWifiManager.getDhcpInfo());
    331         assertEquals(WifiManager.WIFI_STATE_ENABLED, mWifiManager.getWifiState());
    332         mWifiManager.getConnectionInfo();
    333         setWifiEnabled(false);
    334         assertFalse(mWifiManager.isWifiEnabled());
    335     }
    336 
    337     /**
    338      * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with
    339      * {@link SystemClock#elapsedRealtime()} on device.<p>
    340      * To run this test in cts-tradefed:
    341      * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp
    342      */
    343     public void testWifiScanTimestamp() throws Exception {
    344         if (!WifiFeature.isWifiSupported(getContext())) {
    345             Log.d(TAG, "Skipping test as WiFi is not supported");
    346             return;
    347         }
    348         if (!hasLocationFeature()) {
    349             Log.d(TAG, "Skipping test as location is not supported");
    350             return;
    351         }
    352         if (!isLocationEnabled()) {
    353             fail("Please enable location for this test - since Marshmallow WiFi scan results are"
    354                     + " empty when location is disabled!");
    355         }
    356         if (!mWifiManager.isWifiEnabled()) {
    357             setWifiEnabled(true);
    358         }
    359         // Scan multiple times to make sure scan timestamps increase with device timestamp.
    360         for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) {
    361             startScan();
    362             // Make sure at least one AP is found.
    363             assertTrue("mScanResult should not be null. This may be due to a scan timeout",
    364                        mScanResults != null);
    365             assertFalse("empty scan results!", mScanResults.isEmpty());
    366             long nowMillis = SystemClock.elapsedRealtime();
    367             // Keep track of how many APs are fresh in one scan.
    368             int numFreshAps = 0;
    369             for (ScanResult result : mScanResults) {
    370                 long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp);
    371                 if (Math.abs(nowMillis - scanTimeMillis)  < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) {
    372                     numFreshAps++;
    373                 }
    374             }
    375             // At least half of the APs in the scan should be fresh.
    376             int numTotalAps = mScanResults.size();
    377             String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: "
    378                     + numFreshAps;
    379             assertTrue(msg, numFreshAps * 2 >= mScanResults.size());
    380             if (i < WIFI_SCAN_TEST_ITERATIONS - 1) {
    381                 // Wait before running next iteration.
    382                 Thread.sleep(WIFI_SCAN_TEST_INTERVAL_MILLIS);
    383             }
    384         }
    385     }
    386 
    387     // Return true if location is enabled.
    388     private boolean isLocationEnabled() {
    389         return Settings.Secure.getInt(getContext().getContentResolver(),
    390                 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) !=
    391                 Settings.Secure.LOCATION_MODE_OFF;
    392     }
    393 
    394     // Returns true if the device has location feature.
    395     private boolean hasLocationFeature() {
    396         return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION);
    397     }
    398 
    399     /**
    400      * test point of wifiManager NetWork:
    401      * 1.add NetWork
    402      * 2.update NetWork
    403      * 3.remove NetWork
    404      * 4.enable NetWork
    405      * 5.disable NetWork
    406      * 6.configured Networks
    407      * 7.save configure;
    408      */
    409     public void testWifiManagerNetWork() throws Exception {
    410         if (!WifiFeature.isWifiSupported(getContext())) {
    411             // skip the test if WiFi is not supported
    412             return;
    413         }
    414 
    415         // store the list of enabled networks, so they can be re-enabled after test completes
    416         Set<String> enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks());
    417         try {
    418             WifiConfiguration wifiConfiguration;
    419             // add a WifiConfig
    420             final int notExist = -1;
    421             List<WifiConfiguration> wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks();
    422             int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks);
    423             if (notExist != pos) {
    424                 wifiConfiguration = wifiConfiguredNetworks.get(pos);
    425                 mWifiManager.removeNetwork(wifiConfiguration.networkId);
    426             }
    427             pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks);
    428             assertEquals(notExist, pos);
    429             final int size = wifiConfiguredNetworks.size();
    430 
    431             wifiConfiguration = new WifiConfiguration();
    432             wifiConfiguration.SSID = SSID1;
    433             wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
    434             int netId = mWifiManager.addNetwork(wifiConfiguration);
    435             assertTrue(existSSID(SSID1));
    436 
    437             wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks();
    438             assertEquals(size + 1, wifiConfiguredNetworks.size());
    439             pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks);
    440             assertTrue(notExist != pos);
    441 
    442             // Enable & disable network
    443             boolean disableOthers = true;
    444             assertTrue(mWifiManager.enableNetwork(netId, disableOthers));
    445             wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos);
    446             assertEquals(Status.ENABLED, wifiConfiguration.status);
    447 
    448             assertTrue(mWifiManager.disableNetwork(netId));
    449             wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos);
    450             assertEquals(Status.DISABLED, wifiConfiguration.status);
    451 
    452             // Update a WifiConfig
    453             wifiConfiguration = wifiConfiguredNetworks.get(pos);
    454             wifiConfiguration.SSID = SSID2;
    455             netId = mWifiManager.updateNetwork(wifiConfiguration);
    456             assertFalse(existSSID(SSID1));
    457             assertTrue(existSSID(SSID2));
    458 
    459             // Remove a WifiConfig
    460             assertTrue(mWifiManager.removeNetwork(netId));
    461             assertFalse(mWifiManager.removeNetwork(notExist));
    462             assertFalse(existSSID(SSID1));
    463             assertFalse(existSSID(SSID2));
    464 
    465             assertTrue(mWifiManager.saveConfiguration());
    466         } finally {
    467             reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks());
    468             mWifiManager.saveConfiguration();
    469         }
    470     }
    471 
    472     /**
    473      * Verifies that addNetwork() fails for WifiConfigurations containing a non-null http proxy when
    474      * the caller doesn't have OVERRIDE_WIFI_CONFIG permission, DeviceOwner or ProfileOwner device
    475      * management policies
    476      */
    477     public void testSetHttpProxy_PermissionFail() throws Exception {
    478         if (!WifiFeature.isWifiSupported(getContext())) {
    479             // skip the test if WiFi is not supported
    480             return;
    481         }
    482         WifiConfigCreator configCreator = new WifiConfigCreator(getContext());
    483         boolean exceptionThrown = false;
    484         try {
    485             configCreator.addHttpProxyNetworkVerifyAndRemove(
    486                     PROXY_TEST_SSID, TEST_PAC_URL);
    487         } catch (IllegalStateException e) {
    488             // addHttpProxyNetworkVerifyAndRemove throws three IllegalStateException,
    489             // expect it to throw for the addNetwork operation
    490             if (e.getMessage().contains(ADD_NETWORK_EXCEPTION_SUBSTR)) {
    491                 exceptionThrown = true;
    492             }
    493         }
    494         assertTrue(exceptionThrown);
    495     }
    496 
    497     private Set<String> getEnabledNetworks(List<WifiConfiguration> configuredNetworks) {
    498         Set<String> ssids = new HashSet<String>();
    499         for (WifiConfiguration wifiConfig : configuredNetworks) {
    500             if (Status.ENABLED == wifiConfig.status || Status.CURRENT == wifiConfig.status) {
    501                 ssids.add(wifiConfig.SSID);
    502                 Log.i(TAG, String.format("remembering enabled network %s", wifiConfig.SSID));
    503             }
    504         }
    505         return ssids;
    506     }
    507 
    508     private void reEnableNetworks(Set<String> enabledSsids,
    509             List<WifiConfiguration> configuredNetworks) {
    510         for (WifiConfiguration wifiConfig : configuredNetworks) {
    511             if (enabledSsids.contains(wifiConfig.SSID)) {
    512                 mWifiManager.enableNetwork(wifiConfig.networkId, false);
    513                 Log.i(TAG, String.format("re-enabling network %s", wifiConfig.SSID));
    514             }
    515         }
    516     }
    517 
    518     public void testSignal() {
    519         if (!WifiFeature.isWifiSupported(getContext())) {
    520             // skip the test if WiFi is not supported
    521             return;
    522         }
    523         final int numLevels = 9;
    524         int expectLevel = 0;
    525         assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels));
    526         assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels));
    527         expectLevel = 4;
    528         assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2,
    529                 numLevels));
    530         int rssiA = 4;
    531         int rssiB = 5;
    532         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0);
    533         rssiB = 4;
    534         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0);
    535         rssiA = 5;
    536         rssiB = 4;
    537         assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0);
    538     }
    539 
    540     private int getTxPacketCount() throws Exception {
    541         final AtomicInteger ret = new AtomicInteger(-1);
    542 
    543         mWifiManager.getTxPacketCount(new TxPacketCountListener() {
    544             @Override
    545             public void onSuccess(int count) {
    546                 ret.set(count);
    547             }
    548             @Override
    549             public void onFailure(int reason) {
    550                 ret.set(0);
    551             }
    552         });
    553 
    554         long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
    555         while (ret.get() < 0 && System.currentTimeMillis() < timeout)
    556             Thread.sleep(WAIT_MSEC);
    557         assertTrue(ret.get() >= 0);
    558         return ret.get();
    559     }
    560 
    561     /**
    562      * The new WiFi watchdog requires kernel/driver to export some packet loss
    563      * counters. This CTS tests whether those counters are correctly exported.
    564      * To pass this CTS test, a connected WiFi link is required.
    565      */
    566     public void testWifiWatchdog() throws Exception {
    567         if (!WifiFeature.isWifiSupported(getContext())) {
    568             // skip the test if WiFi is not supported
    569             return;
    570         }
    571         // Make sure WiFi is enabled
    572         if (!mWifiManager.isWifiEnabled()) {
    573             setWifiEnabled(true);
    574             Thread.sleep(DURATION);
    575         }
    576         assertTrue(mWifiManager.isWifiEnabled());
    577 
    578         // give the test a chance to autoconnect
    579         Thread.sleep(DURATION);
    580         if (mNetworkInfo.getState() != NetworkInfo.State.CONNECTED) {
    581             // this test requires a connectable network be configured
    582             fail("This test requires a wifi network connection.");
    583         }
    584 
    585         // This will generate a distinct stack trace if the initial connection fails.
    586         connectWifi();
    587 
    588         int i = 0;
    589         for (; i < 15; i++) {
    590             // Wait for a WiFi connection
    591             connectWifi();
    592 
    593             // Read TX packet counter
    594             int txcount1 = getTxPacketCount();
    595 
    596             // Do some network operations
    597             HttpURLConnection connection = null;
    598             try {
    599                 URL url = new URL("http://www.google.com/");
    600                 connection = (HttpURLConnection) url.openConnection();
    601                 connection.setInstanceFollowRedirects(false);
    602                 connection.setConnectTimeout(TIMEOUT_MSEC);
    603                 connection.setReadTimeout(TIMEOUT_MSEC);
    604                 connection.setUseCaches(false);
    605                 connection.getInputStream();
    606             } catch (Exception e) {
    607                 // ignore
    608             } finally {
    609                 if (connection != null) connection.disconnect();
    610             }
    611 
    612             // Read TX packet counter again and make sure it increases
    613             int txcount2 = getTxPacketCount();
    614 
    615             if (txcount2 > txcount1) {
    616                 break;
    617             } else {
    618                 Thread.sleep(DURATION);
    619             }
    620         }
    621         assertTrue(i < 15);
    622     }
    623 
    624     /**
    625      * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint
    626      * configuration with an user credential.
    627      *
    628      * @throws Exception
    629      */
    630     public void testAddPasspointConfigWithUserCredential() throws Exception {
    631         if (!WifiFeature.isWifiSupported(getContext())) {
    632             // skip the test if WiFi is not supported
    633             return;
    634         }
    635         testAddPasspointConfig(generatePasspointConfig(generateUserCredential()));
    636     }
    637 
    638     /**
    639      * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint
    640      * configuration with a certificate credential.
    641      *
    642      * @throws Exception
    643      */
    644     public void testAddPasspointConfigWithCertCredential() throws Exception {
    645         if (!WifiFeature.isWifiSupported(getContext())) {
    646             // skip the test if WiFi is not supported
    647             return;
    648         }
    649         testAddPasspointConfig(generatePasspointConfig(generateCertCredential()));
    650     }
    651 
    652     /**
    653      * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint
    654      * configuration with a SIm credential.
    655      *
    656      * @throws Exception
    657      */
    658     public void testAddPasspointConfigWithSimCredential() throws Exception {
    659         if (!WifiFeature.isWifiSupported(getContext())) {
    660             // skip the test if WiFi is not supported
    661             return;
    662         }
    663         testAddPasspointConfig(generatePasspointConfig(generateSimCredential()));
    664     }
    665 
    666     /**
    667      * Helper function for generating a {@link PasspointConfiguration} for testing.
    668      *
    669      * @return {@link PasspointConfiguration}
    670      */
    671     private PasspointConfiguration generatePasspointConfig(Credential credential) {
    672         PasspointConfiguration config = new PasspointConfiguration();
    673         config.setCredential(credential);
    674 
    675         // Setup HomeSp.
    676         HomeSp homeSp = new HomeSp();
    677         homeSp.setFqdn("Test.com");
    678         homeSp.setFriendlyName("Test Provider");
    679         homeSp.setRoamingConsortiumOis(new long[] {0x11223344});
    680         config.setHomeSp(homeSp);
    681 
    682         return config;
    683     }
    684 
    685     /**
    686      * Helper function for generating an user credential for testing.
    687      *
    688      * @return {@link Credential}
    689      */
    690     private Credential generateUserCredential() {
    691         Credential credential = new Credential();
    692         credential.setRealm("test.net");
    693         Credential.UserCredential userCred = new Credential.UserCredential();
    694         userCred.setEapType(21 /* EAP_TTLS */);
    695         userCred.setUsername("username");
    696         userCred.setPassword("password");
    697         userCred.setNonEapInnerMethod("PAP");
    698         credential.setUserCredential(userCred);
    699         credential.setCaCertificate(FakeKeys.CA_PUBLIC_CERT);
    700         return credential;
    701     }
    702 
    703     /**
    704      * Helper function for generating a certificate credential for testing.
    705      *
    706      * @return {@link Credential}
    707      */
    708     private Credential generateCertCredential() throws Exception {
    709         Credential credential = new Credential();
    710         credential.setRealm("test.net");
    711         Credential.CertificateCredential certCredential = new Credential.CertificateCredential();
    712         certCredential.setCertType("x509v3");
    713         certCredential.setCertSha256Fingerprint(
    714                 MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()));
    715         credential.setCertCredential(certCredential);
    716         credential.setCaCertificate(FakeKeys.CA_PUBLIC_CERT);
    717         credential.setClientCertificateChain(new X509Certificate[] {FakeKeys.CLIENT_CERT});
    718         credential.setClientPrivateKey(FakeKeys.RSA_KEY1);
    719         return credential;
    720     }
    721 
    722     /**
    723      * Helper function for generating a SIM credential for testing.
    724      *
    725      * @return {@link Credential}
    726      */
    727     private Credential generateSimCredential() throws Exception {
    728         Credential credential = new Credential();
    729         credential.setRealm("test.net");
    730         Credential.SimCredential simCredential = new Credential.SimCredential();
    731         simCredential.setImsi("1234*");
    732         simCredential.setEapType(18 /* EAP_SIM */);
    733         credential.setSimCredential(simCredential);
    734         return credential;
    735     }
    736 
    737     /**
    738      * Helper function verifying Passpoint configuration management APIs (add, remove, get) for
    739      * a given configuration.
    740      *
    741      * @param config The configuration to test with
    742      */
    743     private void testAddPasspointConfig(PasspointConfiguration config) throws Exception {
    744         try {
    745 
    746             // obtain number of passpoint networks already present in device (preloaded)
    747             List<PasspointConfiguration> preConfigList = mWifiManager.getPasspointConfigurations();
    748             int numOfNetworks = preConfigList.size();
    749 
    750             // add new (test) configuration
    751             mWifiManager.addOrUpdatePasspointConfiguration(config);
    752 
    753             // Certificates and keys will be set to null after it is installed to the KeyStore by
    754             // WifiManager.  Reset them in the expected config so that it can be used to compare
    755             // against the retrieved config.
    756             config.getCredential().setCaCertificate(null);
    757             config.getCredential().setClientCertificateChain(null);
    758             config.getCredential().setClientPrivateKey(null);
    759 
    760             // retrieve the configuration and verify it. The retrieved list may not be in order -
    761             // check all configs to see if any match
    762             List<PasspointConfiguration> configList = mWifiManager.getPasspointConfigurations();
    763             assertEquals(numOfNetworks + 1, configList.size());
    764 
    765             boolean anyMatch = false;
    766             for (PasspointConfiguration passpointConfiguration : configList) {
    767                 if (passpointConfiguration.equals(config)) {
    768                     anyMatch = true;
    769                     break;
    770                 }
    771             }
    772             assertTrue(anyMatch);
    773 
    774             // remove the (test) configuration and verify number of installed configurations
    775             mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn());
    776             assertEquals(mWifiManager.getPasspointConfigurations().size(), numOfNetworks);
    777         } catch (UnsupportedOperationException e) {
    778             // Passpoint build config |config_wifi_hotspot2_enabled| is disabled, so noop.
    779         }
    780     }
    781 
    782     public class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback {
    783         Object hotspotLock;
    784         WifiManager.LocalOnlyHotspotReservation reservation = null;
    785         boolean onStartedCalled = false;
    786         boolean onStoppedCalled = false;
    787         boolean onFailedCalled = false;
    788         int failureReason = -1;
    789 
    790         TestLocalOnlyHotspotCallback(Object lock) {
    791             hotspotLock = lock;
    792         }
    793 
    794         @Override
    795         public void onStarted(WifiManager.LocalOnlyHotspotReservation r) {
    796             synchronized (hotspotLock) {
    797                 reservation = r;
    798                 onStartedCalled = true;
    799                 hotspotLock.notify();
    800             }
    801         }
    802 
    803         @Override
    804         public void onStopped() {
    805             synchronized (hotspotLock) {
    806                 onStoppedCalled = true;
    807                 hotspotLock.notify();
    808             }
    809         }
    810 
    811         @Override
    812         public void onFailed(int reason) {
    813             synchronized (hotspotLock) {
    814                 onFailedCalled = true;
    815                 failureReason = reason;
    816                 hotspotLock.notify();
    817             }
    818         }
    819     }
    820 
    821     private TestLocalOnlyHotspotCallback startLocalOnlyHotspot() {
    822         // Location mode must be enabled for this test
    823         if (!isLocationEnabled()) {
    824             fail("Please enable location for this test");
    825         }
    826 
    827         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLOHSLock);
    828         synchronized (mLOHSLock) {
    829             try {
    830                 mWifiManager.startLocalOnlyHotspot(callback, null);
    831                 // now wait for callback
    832                 mLOHSLock.wait(DURATION);
    833             } catch (InterruptedException e) {
    834             }
    835             // check if we got the callback
    836             assertTrue(callback.onStartedCalled);
    837             assertNotNull(callback.reservation.getWifiConfiguration());
    838             assertFalse(callback.onFailedCalled);
    839             assertFalse(callback.onStoppedCalled);
    840         }
    841         return callback;
    842     }
    843 
    844     private void stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled) {
    845        synchronized (mMySync) {
    846            // we are expecting a new state
    847            mMySync.expectedState = STATE_WIFI_CHANGING;
    848 
    849            // now shut down LocalOnlyHotspot
    850            callback.reservation.close();
    851 
    852            try {
    853                waitForExpectedWifiState(wifiEnabled);
    854            } catch (InterruptedException e) {}
    855         }
    856     }
    857 
    858     /**
    859      * Verify that calls to startLocalOnlyHotspot succeed with proper permissions.
    860      *
    861      * Note: Location mode must be enabled for this test.
    862      */
    863     public void testStartLocalOnlyHotspotSuccess() {
    864         if (!WifiFeature.isWifiSupported(getContext())) {
    865             // skip the test if WiFi is not supported
    866             return;
    867         }
    868         // check that softap mode is supported by the device
    869         if (!mWifiManager.isPortableHotspotSupported()) {
    870             return;
    871         }
    872 
    873         boolean wifiEnabled = mWifiManager.isWifiEnabled();
    874 
    875         TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
    876 
    877         stopLocalOnlyHotspot(callback, wifiEnabled);
    878 
    879         // wifi should either stay on, or come back on
    880         assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
    881     }
    882 
    883     /**
    884      * Verify calls to setWifiEnabled from a non-settings app while softap mode is active do not
    885      * exit softap mode.
    886      *
    887      * This test uses the LocalOnlyHotspot API to enter softap mode.  This should also be true when
    888      * tethering is started.
    889      * Note: Location mode must be enabled for this test.
    890      */
    891     public void testSetWifiEnabledByAppDoesNotStopHotspot() throws Exception {
    892         if (!WifiFeature.isWifiSupported(getContext())) {
    893             // skip the test if WiFi is not supported
    894             return;
    895         }
    896         // check that softap mode is supported by the device
    897         if (!mWifiManager.isPortableHotspotSupported()) {
    898             return;
    899         }
    900 
    901         boolean wifiEnabled = mWifiManager.isWifiEnabled();
    902 
    903         if (wifiEnabled) {
    904             // disable wifi so we have something to turn on (some devices may be able to run
    905             // simultaneous modes)
    906             setWifiEnabled(false);
    907         }
    908 
    909         TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
    910 
    911         // now we should fail to turn on wifi
    912         assertFalse(mWifiManager.setWifiEnabled(true));
    913 
    914         stopLocalOnlyHotspot(callback, wifiEnabled);
    915     }
    916 
    917     /**
    918      * Verify that applications can only have one registered LocalOnlyHotspot request at a time.
    919      *
    920      * Note: Location mode must be enabled for this test.
    921      */
    922     public void testStartLocalOnlyHotspotSingleRequestByApps() {
    923         if (!WifiFeature.isWifiSupported(getContext())) {
    924             // skip the test if WiFi is not supported
    925             return;
    926         }
    927         // check that softap mode is supported by the device
    928         if (!mWifiManager.isPortableHotspotSupported()) {
    929             return;
    930         }
    931 
    932         boolean caughtException = false;
    933 
    934         boolean wifiEnabled = mWifiManager.isWifiEnabled();
    935 
    936         TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
    937 
    938         // now make a second request - this should fail.
    939         TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLOHSLock);
    940         try {
    941             mWifiManager.startLocalOnlyHotspot(callback2, null);
    942         } catch (IllegalStateException e) {
    943             Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice");
    944             caughtException = true;
    945         }
    946         if (!caughtException) {
    947             // second start did not fail, should clean up the hotspot.
    948             stopLocalOnlyHotspot(callback2, wifiEnabled);
    949         }
    950         assertTrue(caughtException);
    951 
    952         stopLocalOnlyHotspot(callback, wifiEnabled);
    953     }
    954 }
    955