Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2015 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 package com.android.settingslib.wifi;
     17 
     18 import android.content.Intent;
     19 import android.net.NetworkInfo;
     20 import android.net.NetworkInfo.State;
     21 import android.net.wifi.ScanResult;
     22 import android.net.wifi.WifiConfiguration;
     23 import android.net.wifi.WifiInfo;
     24 import android.net.wifi.WifiManager;
     25 import android.net.wifi.WifiSsid;
     26 import android.os.HandlerThread;
     27 import android.os.Looper;
     28 import android.util.Log;
     29 
     30 import com.android.settingslib.BaseTest;
     31 import com.android.settingslib.wifi.WifiTracker.Scanner;
     32 import com.android.settingslib.wifi.WifiTracker.WifiListener;
     33 
     34 import org.mockito.ArgumentCaptor;
     35 import org.mockito.Mockito;
     36 
     37 import java.io.PrintWriter;
     38 import java.io.StringWriter;
     39 import java.util.ArrayList;
     40 import java.util.List;
     41 
     42 public class WifiTrackerTest extends BaseTest {
     43 
     44     private static final String TAG = "WifiTrackerTest";
     45 
     46     private static final String[] TEST_SSIDS = new String[] {
     47         "TEST_SSID_1",
     48         "TEST_SSID_2",
     49         "TEST_SSID_3",
     50         "TEST_SSID_4",
     51         "TEST_SSID_5",
     52     };
     53     private static final int NUM_NETWORKS = 5;
     54 
     55     private WifiManager mWifiManager;
     56     private WifiListener mWifiListener;
     57 
     58     private WifiTracker mWifiTracker;
     59 
     60     private HandlerThread mWorkerThread;
     61     private Looper mLooper;
     62     private HandlerThread mMainThread;
     63     private Looper mMainLooper;
     64 
     65     @Override
     66     protected void setUp() throws Exception {
     67         super.setUp();
     68 
     69         mWifiManager = Mockito.mock(WifiManager.class);
     70         mWifiListener = Mockito.mock(WifiListener.class);
     71         mWorkerThread = new HandlerThread("TestHandlerThread");
     72         mWorkerThread.start();
     73         mLooper = mWorkerThread.getLooper();
     74         mMainThread = new HandlerThread("TestHandlerThread");
     75         mMainThread.start();
     76         mMainLooper = mMainThread.getLooper();
     77         mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, true, true, true,
     78                 mWifiManager, mMainLooper);
     79         mWifiTracker.mScanner = mWifiTracker.new Scanner();
     80         Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(true);
     81     }
     82 
     83     @Override
     84     protected void tearDown() throws Exception {
     85         StringWriter sw = new StringWriter();
     86         PrintWriter pw = new PrintWriter(sw);
     87         mWifiTracker.dump(pw);
     88         pw.flush();
     89         Log.d(TAG, sw.toString());
     90         super.tearDown();
     91     }
     92 
     93     public void testAccessPointsCallback() {
     94         sendScanResultsAndProcess(false);
     95 
     96         Mockito.verify(mWifiListener, Mockito.atLeastOnce()).onAccessPointsChanged();
     97     }
     98 
     99     public void testConnectedCallback() {
    100         sendConnected();
    101         waitForThreads();
    102 
    103         Mockito.verify(mWifiListener, Mockito.atLeastOnce()).onConnectedChanged();
    104         assertEquals(true, mWifiTracker.isConnected());
    105     }
    106 
    107     public void testWifiStateCallback() {
    108         final int TEST_WIFI_STATE = WifiManager.WIFI_STATE_ENABLED;
    109 
    110         Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
    111         i.putExtra(WifiManager.EXTRA_WIFI_STATE, TEST_WIFI_STATE);
    112         mWifiTracker.mReceiver.onReceive(mContext, i);
    113         waitForThreads();
    114 
    115         ArgumentCaptor<Integer> wifiState = ArgumentCaptor.forClass(Integer.class);
    116         Mockito.verify(mWifiListener, Mockito.atLeastOnce())
    117                 .onWifiStateChanged(wifiState.capture());
    118         assertEquals(TEST_WIFI_STATE, (int) wifiState.getValue());
    119     }
    120 
    121     public void testScanner() {
    122         // TODO: Figure out how to verify more of the Scanner functionality.
    123         // Make scans be successful.
    124         Mockito.when(mWifiManager.startScan()).thenReturn(true);
    125 
    126         mWifiTracker.mScanner.handleMessage(mWifiTracker.mScanner.obtainMessage(Scanner.MSG_SCAN));
    127         Mockito.verify(mWifiManager, Mockito.atLeastOnce()).startScan();
    128     }
    129 
    130     public void testNetworkSorting() {
    131         List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
    132         List<ScanResult> scanResults = new ArrayList<ScanResult>();
    133         String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, true);
    134 
    135         // Tell WifiTracker we are connected now.
    136         sendConnected();
    137 
    138         // Send all of the configs and scan results to the tracker.
    139         Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
    140         Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
    141         sendScanResultsAndProcess(false);
    142 
    143         List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
    144         assertEquals("Expected number of results", NUM_NETWORKS, accessPoints.size());
    145         for (int i = 0; i < NUM_NETWORKS; i++) {
    146             assertEquals("Verifying slot " + i, expectedSsids[i], accessPoints.get(i).getSsid());
    147         }
    148     }
    149 
    150     public void testSavedOnly() {
    151         mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, true, false, true,
    152                 mWifiManager, mMainLooper);
    153         mWifiTracker.mScanner = mWifiTracker.new Scanner();
    154 
    155         List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
    156         List<ScanResult> scanResults = new ArrayList<ScanResult>();
    157         generateTestNetworks(wifiConfigs, scanResults, true);
    158 
    159         // Tell WifiTracker we are connected now.
    160         sendConnected();
    161 
    162         // Send all of the configs and scan results to the tracker.
    163         Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
    164         Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
    165         sendScanResultsAndProcess(false);
    166 
    167         List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
    168         // Only expect the first two to come back in the results.
    169         assertEquals("Expected number of results", 2, accessPoints.size());
    170         assertEquals(TEST_SSIDS[1], accessPoints.get(0).getSsid());
    171         assertEquals(TEST_SSIDS[0], accessPoints.get(1).getSsid());
    172     }
    173 
    174     /**
    175      * This tests the case where Settings runs this on a non-looper thread for indexing.
    176      */
    177     public void testSavedOnlyNoLooper() {
    178         mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, true, false, true,
    179                 mWifiManager,  null);
    180         mWifiTracker.mScanner = mWifiTracker.new Scanner();
    181 
    182         List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
    183         List<ScanResult> scanResults = new ArrayList<ScanResult>();
    184         generateTestNetworks(wifiConfigs, scanResults, true);
    185 
    186         // Send all of the configs and scan results to the tracker.
    187         Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
    188         Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
    189         mWifiTracker.forceUpdate();
    190 
    191         List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
    192         // Only expect the first two to come back in the results.
    193         assertEquals("Expected number of results", 2, accessPoints.size());
    194         assertEquals(TEST_SSIDS[1], accessPoints.get(0).getSsid());
    195         assertEquals(TEST_SSIDS[0], accessPoints.get(1).getSsid());
    196     }
    197 
    198     public void testAvailableOnly() {
    199         mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, false, true, true,
    200                 mWifiManager, mMainLooper);
    201         mWifiTracker.mScanner = mWifiTracker.new Scanner();
    202 
    203         List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
    204         List<ScanResult> scanResults = new ArrayList<ScanResult>();
    205         String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, true);
    206 
    207         // Tell WifiTracker we are connected now.
    208         sendConnected();
    209 
    210         // Send all of the configs and scan results to the tracker.
    211         Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
    212         Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
    213         sendScanResultsAndProcess(false);
    214 
    215         // Expect the last one (sorted order) to be left off since its only saved.
    216         List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
    217         assertEquals("Expected number of results", NUM_NETWORKS - 1, accessPoints.size());
    218         for (int i = 0; i < NUM_NETWORKS - 1; i++) {
    219             assertEquals("Verifying slot " + i, expectedSsids[i], accessPoints.get(i).getSsid());
    220         }
    221     }
    222 
    223     public void testNonEphemeralConnected() {
    224         mWifiTracker = new WifiTracker(mContext, mWifiListener, mLooper, false, true, true,
    225                 mWifiManager, mMainLooper);
    226         mWifiTracker.mScanner = mWifiTracker.new Scanner();
    227 
    228         List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
    229         List<ScanResult> scanResults = new ArrayList<ScanResult>();
    230         generateTestNetworks(wifiConfigs, scanResults, false);
    231 
    232         // Tell WifiTracker we are connected now.
    233         sendConnected();
    234 
    235         // Send all of the configs and scan results to the tracker.
    236         Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
    237         Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
    238         // Do this twice to catch a bug that was happening in the caching, making things ephemeral.
    239         sendScanResultsAndProcess(true);
    240 
    241         List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
    242         assertEquals("Expected number of results", NUM_NETWORKS - 1, accessPoints.size());
    243         assertFalse("Connection is not ephemeral", accessPoints.get(0).isEphemeral());
    244         assertTrue("Connected to wifi", accessPoints.get(0).isActive());
    245     }
    246 
    247     public void testEnableResumeScanning() {
    248         mWifiTracker.mScanner = null;
    249 
    250         Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
    251         // Make sure disable/enable cycle works with no scanner (no crashing).
    252         i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
    253         mWifiTracker.mReceiver.onReceive(mContext, i);
    254         i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
    255         mWifiTracker.mReceiver.onReceive(mContext, i);
    256 
    257         Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(false);
    258         i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
    259         mWifiTracker.mReceiver.onReceive(mContext, i);
    260         // Now enable scanning while wifi is off, it shouldn't start.
    261         mWifiTracker.resumeScanning();
    262         assertFalse(mWifiTracker.mScanner.isScanning());
    263 
    264         // Turn on wifi and make sure scanning starts.
    265         i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
    266         mWifiTracker.mReceiver.onReceive(mContext, i);
    267         assertTrue(mWifiTracker.mScanner.isScanning());
    268     }
    269 
    270     private String[] generateTestNetworks(List<WifiConfiguration> wifiConfigs,
    271             List<ScanResult> scanResults, boolean connectedIsEphemeral) {
    272         String[] expectedSsids = new String[NUM_NETWORKS];
    273 
    274         // First is just saved;
    275         addConfig(wifiConfigs, TEST_SSIDS[0]);
    276         // This should come last since its not available.
    277         expectedSsids[4] = TEST_SSIDS[0];
    278 
    279         // Second is saved and available.
    280         addConfig(wifiConfigs, TEST_SSIDS[1]);
    281         addResult(scanResults, TEST_SSIDS[1], 0);
    282         // This one is going to have a couple extra results, to verify de-duplication.
    283         addResult(scanResults, TEST_SSIDS[1], 2);
    284         addResult(scanResults, TEST_SSIDS[1], 1);
    285         // This should come second since it is available and saved but not connected.
    286         expectedSsids[1] = TEST_SSIDS[1];
    287 
    288         // Third is just available, but higher rssi.
    289         addResult(scanResults, TEST_SSIDS[2], 3);
    290         // This comes after the next one since it has a lower rssi.
    291         expectedSsids[3] = TEST_SSIDS[2];
    292 
    293         // Fourth also just available but with even higher rssi.
    294         addResult(scanResults, TEST_SSIDS[3], 4);
    295         // This is the highest rssi but not saved so it should be after the saved+availables.
    296         expectedSsids[2] = TEST_SSIDS[3];
    297 
    298         // Last is going to be connected.
    299         int netId = WifiConfiguration.INVALID_NETWORK_ID;
    300         if (!connectedIsEphemeral) {
    301             netId = addConfig(wifiConfigs, TEST_SSIDS[4]);
    302         }
    303         addResult(scanResults, TEST_SSIDS[4], 2);
    304         // Setup wifi connection to be this one.
    305         WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
    306         Mockito.when(wifiInfo.getSSID()).thenReturn(TEST_SSIDS[4]);
    307         Mockito.when(wifiInfo.getNetworkId()).thenReturn(netId);
    308         Mockito.when(mWifiManager.getConnectionInfo()).thenReturn(wifiInfo);
    309         // This should come first since it is connected.
    310         expectedSsids[0] = TEST_SSIDS[4];
    311 
    312         return expectedSsids;
    313     }
    314 
    315     private void addResult(List<ScanResult> results, String ssid, int level) {
    316         results.add(new ScanResult(WifiSsid.createFromAsciiEncoded(ssid),
    317                 ssid, ssid, levelToRssi(level), AccessPoint.LOWER_FREQ_24GHZ, 0));
    318     }
    319 
    320     public static int levelToRssi(int level) {
    321         // Reverse level to rssi calculation based off from WifiManager.calculateSignalLevel.
    322         final int MAX_RSSI = -55;
    323         final int MIN_RSSI = -100;
    324         final int NUM_LEVELS = 4;
    325         return level * (MAX_RSSI - MIN_RSSI) / (NUM_LEVELS - 1) + MIN_RSSI;
    326     }
    327 
    328     private int addConfig(List<WifiConfiguration> configs, String ssid) {
    329         WifiConfiguration config = new WifiConfiguration();
    330         config.networkId = configs.size();
    331         config.SSID = '"' + ssid + '"';
    332         configs.add(config);
    333         return config.networkId;
    334     }
    335 
    336     private void sendConnected() {
    337         NetworkInfo networkInfo = Mockito.mock(NetworkInfo.class);
    338         Mockito.when(networkInfo.isConnected()).thenReturn(true);
    339         Mockito.when(networkInfo.getState()).thenReturn(State.CONNECTED);
    340         Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    341         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
    342         mWifiTracker.mReceiver.onReceive(mContext, intent);
    343     }
    344 
    345     private void sendScanResultsAndProcess(boolean sendTwice) {
    346         Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
    347         mWifiTracker.mReceiver.onReceive(mContext, i);
    348         if (sendTwice) {
    349             mWifiTracker.mReceiver.onReceive(mContext, i);
    350         }
    351         waitForThreads();
    352     }
    353 
    354     private void waitForThreads() {
    355         // Run all processing.
    356         mWorkerThread.quitSafely();
    357         try {
    358             mWorkerThread.join();
    359         } catch (InterruptedException e) {
    360         }
    361         // Send all callbacks.
    362         mMainThread.quitSafely();
    363         try {
    364             mMainThread.join();
    365         } catch (InterruptedException e) {
    366         }
    367     }
    368 
    369 }
    370