ScanResults.java revision 63539f1283899fbbf83ab90757961b4be51d5034
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 17package com.android.server.wifi; 18 19import android.net.wifi.ScanResult; 20import android.net.wifi.WifiScanner.ScanData; 21import android.net.wifi.WifiSsid; 22 23import com.android.server.wifi.hotspot2.NetworkDetail; 24 25import java.math.BigInteger; 26import java.nio.charset.Charset; 27import java.util.ArrayList; 28import java.util.Arrays; 29import java.util.Comparator; 30import java.util.List; 31import java.util.Random; 32 33/** 34 * Utility for creating scan results from a scan 35 */ 36public class ScanResults { 37 private final ArrayList<ScanDetail> mScanDetails = new ArrayList<>(); 38 private final ScanData mScanData; 39 private final ScanResult[] mScanResults; 40 41 private static String generateBssid(Random r) { 42 return String.format("%02X:%02X:%02X:%02X:%02X:%02X", 43 r.nextInt(256), r.nextInt(256), r.nextInt(256), 44 r.nextInt(256), r.nextInt(256), r.nextInt(256)); 45 } 46 47 private static final Comparator<ScanResult> SCAN_RESULT_RSSI_COMPARATOR = 48 new Comparator<ScanResult>() { 49 public int compare(ScanResult r1, ScanResult r2) { 50 return r2.level - r1.level; 51 } 52 }; 53 54 public static ScanResult.InformationElement generateSsidIe(String ssid) { 55 ScanResult.InformationElement ie = new ScanResult.InformationElement(); 56 ie.id = ScanResult.InformationElement.EID_SSID; 57 ie.bytes = ssid.getBytes(Charset.forName("UTF-8")); 58 return ie; 59 } 60 61 /** 62 * Generates an array of random ScanDetails with the given frequencies, seeded by the provided 63 * seed value and test method name and class (annotated with @Test). This method will be 64 * consistent between calls in the same test across runs. 65 * 66 * @param seed combined with a hash of the test method this seeds the random number generator 67 * @param freqs list of frequencies for the generated scan results, these will map 1 to 1 to 68 * to the returned scan details. Duplicates can be specified to create multiple 69 * ScanDetails with the same frequency. 70 */ 71 private static ScanDetail[] generateNativeResults(int seed, int... freqs) { 72 ScanDetail[] results = new ScanDetail[freqs.length]; 73 // Seed the results based on the provided seed as well as the test method name 74 // This provides more varied scan results between individual tests that are very similar. 75 Random r = new Random(seed + WifiTestUtil.getTestMethod().hashCode()); 76 for (int i = 0; i < freqs.length; ++i) { 77 int freq = freqs[i]; 78 String ssid = new BigInteger(128, r).toString(36); 79 String bssid = generateBssid(r); 80 int rssi = r.nextInt(40) - 99; // -99 to -60 81 ScanResult.InformationElement ie[] = new ScanResult.InformationElement[1]; 82 ie[0] = generateSsidIe(ssid); 83 List<String> anqpLines = new ArrayList<>(); 84 NetworkDetail nd = new NetworkDetail(bssid, ie, anqpLines, freq); 85 ScanDetail detail = new ScanDetail(nd, WifiSsid.createFromAsciiEncoded(ssid), 86 bssid, "", rssi, freq, 87 Long.MAX_VALUE, /* needed so that scan results aren't rejected because 88 they are older than scan start */ 89 ie, anqpLines); 90 results[i] = detail; 91 } 92 return results; 93 } 94 95 /** 96 * Create a ScanResults with randomly generated results seeded by the id. 97 * @see #generateNativeResults for more details on how results are generated 98 */ 99 public static ScanResults create(int id, int... freqs) { 100 return new ScanResults(id, -1, generateNativeResults(id, freqs)); 101 } 102 103 /** 104 * Create a ScanResults with the given ScanDetails 105 */ 106 public static ScanResults create(int id, ScanDetail... nativeResults) { 107 return new ScanResults(id, -1, nativeResults); 108 } 109 110 /** 111 * Create scan results that contain all results for the native results and 112 * full scan results, but limits the number of onResults results after sorting 113 * by RSSI 114 */ 115 public static ScanResults createOverflowing(int id, int maxResults, 116 ScanDetail... nativeResults) { 117 return new ScanResults(id, maxResults, nativeResults); 118 } 119 120 private ScanResults(int id, int maxResults, ScanDetail... nativeResults) { 121 mScanResults = new ScanResult[nativeResults.length]; 122 for (int i = 0; i < nativeResults.length; ++i) { 123 mScanDetails.add(nativeResults[i]); 124 mScanResults[i] = nativeResults[i].getScanResult(); 125 } 126 ScanResult[] sortedScanResults = Arrays.copyOf(mScanResults, mScanResults.length); 127 Arrays.sort(sortedScanResults, SCAN_RESULT_RSSI_COMPARATOR); 128 if (maxResults == -1) { 129 mScanData = new ScanData(id, 0, sortedScanResults); 130 } else { 131 ScanResult[] reducedScanResults = Arrays.copyOf(sortedScanResults, 132 Math.min(sortedScanResults.length, maxResults)); 133 mScanData = new ScanData(id, 0, reducedScanResults); 134 } 135 } 136 137 public ArrayList<ScanDetail> getScanDetailArrayList() { 138 return mScanDetails; 139 } 140 141 public ScanData getScanData() { 142 return mScanData; 143 } 144 145 public ScanResult[] getRawScanResults() { 146 return mScanResults; 147 } 148} 149