summaryrefslogtreecommitdiffstats
path: root/tests/wifitests/src/com/android/server/wifi/ScanResults.java
blob: fc532701f0b5be05958055e919aae4a91fae33a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wifi;

import android.net.wifi.ScanResult;
import android.net.wifi.WifiScanner.ScanData;
import android.net.wifi.WifiSsid;

import com.android.server.wifi.hotspot2.NetworkDetail;

import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

/**
 * Utility for creating scan results from a scan
 */
public class ScanResults {
    private final ArrayList<ScanDetail> mScanDetails = new ArrayList<>();
    private final ScanData mScanData;
    private final ScanData mRawScanData;
    private final ScanResult[] mScanResults;

    private ScanResults(ArrayList<ScanDetail> scanDetails, ScanData scanData,
            ScanResult[] scanResults) {
        mScanDetails.addAll(scanDetails);
        mScanData = scanData;
        mRawScanData = scanData;
        mScanResults = scanResults;
    }

    /**
     * Merge the results contained in a number of ScanResults into a single ScanResults
     */
    public static ScanResults merge(ScanResults... others) {
        ArrayList<ScanDetail> scanDetails = new ArrayList<>();
        ArrayList<ScanResult> scanDataResults = new ArrayList<>();
        ArrayList<ScanResult> rawScanResults = new ArrayList<>();
        for (ScanResults other : others) {
            scanDetails.addAll(other.getScanDetailArrayList());
            scanDataResults.addAll(Arrays.asList(other.getScanData().getResults()));
            rawScanResults.addAll(Arrays.asList(other.getRawScanResults()));
        }
        Collections.sort(scanDataResults, SCAN_RESULT_RSSI_COMPARATOR);
        int id = others[0].getScanData().getId();
        return new ScanResults(scanDetails, new ScanData(id, 0, scanDataResults
                        .toArray(new ScanResult[scanDataResults.size()])),
                rawScanResults.toArray(new ScanResult[rawScanResults.size()]));
    }

    private static String generateBssid(Random r) {
        return String.format("%02X:%02X:%02X:%02X:%02X:%02X",
                r.nextInt(256), r.nextInt(256), r.nextInt(256),
                r.nextInt(256), r.nextInt(256), r.nextInt(256));
    }

    public static final Comparator<ScanResult> SCAN_RESULT_RSSI_COMPARATOR =
            new Comparator<ScanResult>() {
        public int compare(ScanResult r1, ScanResult r2) {
            return r2.level - r1.level;
        }
    };

    public static ScanResult.InformationElement generateSsidIe(String ssid) {
        ScanResult.InformationElement ie = new ScanResult.InformationElement();
        ie.id = ScanResult.InformationElement.EID_SSID;
        ie.bytes = ssid.getBytes(Charset.forName("UTF-8"));
        return ie;
    }

    /**
     * Generates an array of random ScanDetails with the given frequencies, seeded by the provided
     * seed value and test method name and class (annotated with @Test). This method will be
     * consistent between calls in the same test across runs.
     *
     * @param seed combined with a hash of the test method this seeds the random number generator
     * @param freqs list of frequencies for the generated scan results, these will map 1 to 1 to
     *              to the returned scan details. Duplicates can be specified to create multiple
     *              ScanDetails with the same frequency.
     */
    private static ScanDetail[] generateNativeResults(boolean needIE, int seed, int... freqs) {
        ScanDetail[] results = new ScanDetail[freqs.length];
        // Seed the results based on the provided seed as well as the test method name
        // This provides more varied scan results between individual tests that are very similar.
        Random r = new Random(seed + WifiTestUtil.getTestMethod().hashCode());
        for (int i = 0; i < freqs.length; ++i) {
            int freq = freqs[i];
            String ssid = new BigInteger(128, r).toString(36);
            String bssid = generateBssid(r);
            int rssi = r.nextInt(40) - 99; // -99 to -60
            ScanResult.InformationElement[] ie;
            if (needIE) {
                ie = new ScanResult.InformationElement[1];
                ie[0] = generateSsidIe(ssid);
            } else {
                ie = new ScanResult.InformationElement[0];
            }
            List<String> anqpLines = new ArrayList<>();
            NetworkDetail nd = new NetworkDetail(bssid, ie, anqpLines, freq);
            ScanDetail detail = new ScanDetail(nd, WifiSsid.createFromAsciiEncoded(ssid),
                    bssid, "", rssi, freq,
                    Long.MAX_VALUE, /* needed so that scan results aren't rejected because
                                        they are older than scan start */
                    ie, anqpLines);
            results[i] = detail;
        }
        return results;
    }

    /**
     * Create scan results with no IE information.
     */
    public static ScanDetail[] generateNativeResults(int seed, int... freqs) {
        return generateNativeResults(true, seed, freqs);
    }

    /**
     * Create a ScanResults with randomly generated results seeded by the id.
     * @see #generateNativeResults for more details on how results are generated
     */
    public static ScanResults create(int id, int... freqs) {
        return create(id, generateNativeResults(id, freqs));
    }
    public static ScanResults create(int id, boolean allChannelsScanned, int... freqs) {
        return create(id, allChannelsScanned, generateNativeResults(id, freqs));
    }

    /**
     * Create a ScanResults with no IE information.
     */
    public static ScanResults createWithNoIE(int id, int... freqs) {
        return create(id, generateNativeResults(false, id, freqs));
    }

    /**
     * Create a ScanResults with the given ScanDetails
     */
    public static ScanResults create(int id, ScanDetail... nativeResults) {
        return new ScanResults(id, false, -1, nativeResults);
    }

    public static ScanResults create(int id, boolean allChannelsScanned,
            ScanDetail... nativeResults) {
        return new ScanResults(id, allChannelsScanned, -1, nativeResults);
    }

    /**
     * Create scan results that contain all results for the native results and
     * full scan results, but limits the number of onResults results after sorting
     * by RSSI
     */
    public static ScanResults createOverflowing(int id, int maxResults,
            ScanDetail... nativeResults) {
        return new ScanResults(id, false, maxResults, nativeResults);
    }

    private ScanResults(int id, boolean allChannelsScanned, int maxResults,
            ScanDetail... nativeResults) {
        mScanResults = new ScanResult[nativeResults.length];
        for (int i = 0; i < nativeResults.length; ++i) {
            mScanDetails.add(nativeResults[i]);
            mScanResults[i] = nativeResults[i].getScanResult();
        }
        ScanResult[] sortedScanResults = Arrays.copyOf(mScanResults, mScanResults.length);
        Arrays.sort(sortedScanResults, SCAN_RESULT_RSSI_COMPARATOR);
        mRawScanData = new ScanData(id, 0, 0, allChannelsScanned, sortedScanResults);
        if (maxResults == -1) {
            mScanData = mRawScanData;
        } else {
            ScanResult[] reducedScanResults = Arrays.copyOf(sortedScanResults,
                    Math.min(sortedScanResults.length, maxResults));
            mScanData = new ScanData(id, 0, 0, allChannelsScanned, reducedScanResults);
        }
    }

    public ArrayList<ScanDetail> getScanDetailArrayList() {
        return mScanDetails;
    }

    public ScanData getScanData() {
        return mScanData;
    }

    public ScanResult[] getRawScanResults() {
        return mScanResults;
    }

    public ScanData getRawScanData() {
        return mRawScanData;
    }
}