1 /* 2 * Copyright (C) 2019 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.cts.verifier.wifi; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.net.wifi.ScanResult; 27 import android.net.wifi.SupplicantState; 28 import android.net.wifi.WifiInfo; 29 import android.net.wifi.WifiManager; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 import com.android.cts.verifier.R; 34 35 import java.lang.annotation.Retention; 36 import java.lang.annotation.RetentionPolicy; 37 import java.util.List; 38 import java.util.Random; 39 import java.util.concurrent.CountDownLatch; 40 import java.util.concurrent.TimeUnit; 41 42 /** 43 * Test utility methods. 44 */ 45 public class TestUtils { 46 private static final String TAG = "NetworkRequestTestCase"; 47 private static final boolean DBG = true; 48 private static final int SCAN_TIMEOUT_MS = 30_000; 49 50 private final Context mContext; 51 protected BaseTestCase.Listener mListener; 52 private final WifiManager mWifiManager; 53 TestUtils(Context context, BaseTestCase.Listener listener)54 public TestUtils(Context context, BaseTestCase.Listener listener) { 55 mContext = context; 56 mListener = listener; 57 mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 58 } 59 startScanAndWaitForResults()60 private boolean startScanAndWaitForResults() throws InterruptedException { 61 IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 62 final CountDownLatch countDownLatch = new CountDownLatch(1); 63 // Scan Results available broadcast receiver. 64 BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { 65 @Override 66 public void onReceive(Context context, Intent intent) { 67 if (DBG) Log.v(TAG, "Broadcast onReceive " + intent); 68 if (!intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) return; 69 if (!intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) return; 70 if (DBG) Log.v(TAG, "Scan results received"); 71 countDownLatch.countDown(); 72 } 73 }; 74 // Register the receiver for scan results broadcast. 75 mContext.registerReceiver(broadcastReceiver, intentFilter); 76 77 // Start scan. 78 if (DBG) Log.v(TAG, "Starting scan"); 79 mListener.onTestMsgReceived(mContext.getString(R.string.wifi_status_initiating_scan)); 80 if (!mWifiManager.startScan()) { 81 Log.e(TAG, "Failed to start scan"); 82 // Unregister the receiver for scan results broadcast. 83 mContext.unregisterReceiver(broadcastReceiver); 84 return false; 85 } 86 // Wait for scan results. 87 if (DBG) Log.v(TAG, "Wait for scan results"); 88 if (!countDownLatch.await(SCAN_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 89 Log.e(TAG, "No new scan results available"); 90 // Unregister the receiver for scan results broadcast. 91 mContext.unregisterReceiver(broadcastReceiver); 92 return false; 93 } 94 95 // Unregister the receiver for scan results broadcast. 96 mContext.unregisterReceiver(broadcastReceiver); 97 return true; 98 } 99 100 public static final int SCAN_RESULT_TYPE_OPEN = 0; 101 public static final int SCAN_RESULT_TYPE_PSK = 1; 102 103 @IntDef(prefix = { "SCAN_RESULT_TYPE_" }, value = { 104 SCAN_RESULT_TYPE_OPEN, 105 SCAN_RESULT_TYPE_PSK, 106 }) 107 @Retention(RetentionPolicy.SOURCE) 108 public @interface ScanResultType {} 109 110 /** 111 * Helper to check if the scan result corresponds to an open network. 112 */ isScanResultForOpenNetwork(@onNull ScanResult scanResult)113 public static boolean isScanResultForOpenNetwork(@NonNull ScanResult scanResult) { 114 String capabilities = scanResult.capabilities; 115 return !capabilities.contains("PSK") && !capabilities.contains("EAP") 116 && !capabilities.contains("WEP") && !capabilities.contains("SAE") 117 && !capabilities.contains("SUITE-B-192") && !capabilities.contains("OWE"); 118 } 119 120 /** 121 * Helper to check if the scan result corresponds to a WPA2 PSK network. 122 */ isScanResultForWpa2Network(@onNull ScanResult scanResult)123 public static boolean isScanResultForWpa2Network(@NonNull ScanResult scanResult) { 124 String capabilities = scanResult.capabilities; 125 return capabilities.contains("PSK"); 126 } 127 128 /** 129 * Helper to check if the scan result corresponds to a WPA3 PSK network. 130 */ isScanResultForWpa3Network(@onNull ScanResult scanResult)131 public static boolean isScanResultForWpa3Network(@NonNull ScanResult scanResult) { 132 String capabilities = scanResult.capabilities; 133 return capabilities.contains("SAE"); 134 } 135 doesScanResultMatchType( ScanResult scanResult, @ScanResultType int type)136 private static boolean doesScanResultMatchType( 137 ScanResult scanResult, @ScanResultType int type) { 138 switch(type) { 139 case SCAN_RESULT_TYPE_OPEN: 140 return isScanResultForOpenNetwork(scanResult); 141 case SCAN_RESULT_TYPE_PSK: 142 return isScanResultForWpa2Network(scanResult) 143 || isScanResultForWpa3Network(scanResult); 144 default: 145 return false; 146 } 147 } 148 149 /** 150 * Helper method to start a scan and find any type of networks in the scan results returned by 151 * the device. 152 * @return ScanResult instance corresponding to an network of type if one exists, null if the 153 * scan failed or if there are networks found. 154 */ startScanAndFindAnyMatchingNetworkInResults( String ssid, @ScanResultType int type)155 public @Nullable ScanResult startScanAndFindAnyMatchingNetworkInResults( 156 String ssid, @ScanResultType int type) 157 throws InterruptedException { 158 // Start scan and wait for new results. 159 if (!startScanAndWaitForResults()) { 160 Log.e(TAG,"Failed to initiate a new scan. Using cached results from device"); 161 } 162 // Filter results to find an open network. 163 List<ScanResult> scanResults = mWifiManager.getScanResults(); 164 for (ScanResult scanResult : scanResults) { 165 if (TextUtils.equals(ssid, scanResult.SSID) 166 && !TextUtils.isEmpty(scanResult.BSSID) 167 && doesScanResultMatchType(scanResult, type)) { 168 if (DBG) Log.v(TAG, "Found network " + scanResult); 169 return scanResult; 170 } 171 } 172 Log.e(TAG, "No matching network found in scan results"); 173 return null; 174 } 175 176 /** 177 * Helper method to check if a scan result with the specified SSID & BSSID matches the scan 178 * results returned by the device. 179 * 180 * @param ssid SSID of the network. 181 * @param bssid BSSID of network. 182 * @return true if there is a match, false otherwise. 183 */ findNetworkInScanResultsResults(@onNull String ssid, @NonNull String bssid)184 public boolean findNetworkInScanResultsResults(@NonNull String ssid, @NonNull String bssid) { 185 List<ScanResult> scanResults = mWifiManager.getScanResults(); 186 for (ScanResult scanResult : scanResults) { 187 if (TextUtils.equals(scanResult.SSID, ssid) 188 && TextUtils.equals(scanResult.BSSID, bssid)) { 189 if (DBG) Log.v(TAG, "Found network " + scanResult); 190 return true; 191 } 192 } 193 return false; 194 } 195 196 /** 197 * Checks whether the device is connected. 198 * 199 * @param ssid If ssid is specified, then check where the device is connected to a network 200 * with the specified SSID. 201 * @param bssid If bssid is specified, then check where the device is connected to a network 202 * with the specified BSSID. 203 * @return true if the device is connected to a network with the specified params, false 204 * otherwise. 205 */ isConnected(@ullable String ssid, @Nullable String bssid)206 public boolean isConnected(@Nullable String ssid, @Nullable String bssid) { 207 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 208 if (wifiInfo == null) { 209 Log.e(TAG, "Failed to get WifiInfo"); 210 return false; 211 } 212 if (wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) return false; 213 if (ssid != null && !wifiInfo.getSSID().equals(ssid)) return false; 214 if (bssid != null && !wifiInfo.getBSSID().equals(bssid)) return false; 215 return true; 216 } 217 218 /** 219 * Generate random passphrase to use for tests. 220 * @return 221 */ generateRandomPassphrase()222 public String generateRandomPassphrase() { 223 return new Random().ints('a', 'z' + 1) 224 .limit(45) 225 .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) 226 .toString(); 227 } 228 } 229