Move ScanResultMatchInfo to its own class

This class is a useful way of grouping scan results into the networks
they represent, agnostic of BSSID. Shifting it so it can be used in
WifiMetrics.

Bug: 36819798
Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh
Change-Id: Ie4fdb488c7a7cb198e16cd5ba72c354045fbc312
diff --git a/service/java/com/android/server/wifi/ConfigurationMap.java b/service/java/com/android/server/wifi/ConfigurationMap.java
index d377f0f..0652b40 100644
--- a/service/java/com/android/server/wifi/ConfigurationMap.java
+++ b/service/java/com/android/server/wifi/ConfigurationMap.java
@@ -5,13 +5,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
-import com.android.server.wifi.util.ScanResultUtil;
-
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Objects;
 
 public class ConfigurationMap {
     private final Map<Integer, WifiConfiguration> mPerID = new HashMap<>();
@@ -120,83 +117,4 @@
     public Collection<WifiConfiguration> valuesForCurrentUser() {
         return mPerIDForCurrentUser.values();
     }
-
-    /**
-     * Class to store the info needed to match a scan result to the provided network configuration.
-     */
-    private static class ScanResultMatchInfo {
-        private static final int NETWORK_TYPE_OPEN = 0;
-        private static final int NETWORK_TYPE_WEP = 1;
-        private static final int NETWORK_TYPE_PSK = 2;
-        private static final int NETWORK_TYPE_EAP = 3;
-
-        /**
-         * SSID of the network.
-         */
-        public String networkSsid;
-        /**
-         * Security Type of the network.
-         */
-        public int networkType;
-
-        public static ScanResultMatchInfo fromWifiConfiguration(WifiConfiguration config) {
-            ScanResultMatchInfo info = new ScanResultMatchInfo();
-            info.networkSsid = config.SSID;
-            if (WifiConfigurationUtil.isConfigForPskNetwork(config)) {
-                info.networkType = NETWORK_TYPE_PSK;
-            } else if (WifiConfigurationUtil.isConfigForEapNetwork(config)) {
-                info.networkType = NETWORK_TYPE_EAP;
-            } else if (WifiConfigurationUtil.isConfigForWepNetwork(config)) {
-                info.networkType = NETWORK_TYPE_WEP;
-            } else if (WifiConfigurationUtil.isConfigForOpenNetwork(config)) {
-                info.networkType = NETWORK_TYPE_OPEN;
-            } else {
-                throw new IllegalArgumentException("Invalid WifiConfiguration: " + config);
-            }
-            return info;
-        }
-
-        public static ScanResultMatchInfo fromScanResult(ScanResult scanResult) {
-            ScanResultMatchInfo info = new ScanResultMatchInfo();
-            // Scan result ssid's are not quoted, hence add quotes.
-            // TODO: This matching algo works only if the scan result contains a string SSID.
-            // However, according to our public documentation ths {@link WifiConfiguration#SSID} can
-            // either have a hex string or quoted ASCII string SSID.
-            info.networkSsid = ScanResultUtil.createQuotedSSID(scanResult.SSID);
-            if (ScanResultUtil.isScanResultForPskNetwork(scanResult)) {
-                info.networkType = NETWORK_TYPE_PSK;
-            } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
-                info.networkType = NETWORK_TYPE_EAP;
-            } else if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
-                info.networkType = NETWORK_TYPE_WEP;
-            } else if (ScanResultUtil.isScanResultForOpenNetwork(scanResult)) {
-                info.networkType = NETWORK_TYPE_OPEN;
-            } else {
-                throw new IllegalArgumentException("Invalid ScanResult: " + scanResult);
-            }
-            return info;
-        }
-
-        @Override
-        public boolean equals(Object otherObj) {
-            if (this == otherObj) {
-                return true;
-            } else if (!(otherObj instanceof ScanResultMatchInfo)) {
-                return false;
-            }
-            ScanResultMatchInfo other = (ScanResultMatchInfo) otherObj;
-            return Objects.equals(networkSsid, other.networkSsid)
-                    && networkType == other.networkType;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(networkSsid, networkType);
-        }
-
-        @Override
-        public String toString() {
-            return "ScanResultMatchInfo: " + networkSsid + ", type: " + networkType;
-        }
-    }
 }
diff --git a/service/java/com/android/server/wifi/ScanResultMatchInfo.java b/service/java/com/android/server/wifi/ScanResultMatchInfo.java
new file mode 100644
index 0000000..ad29c23
--- /dev/null
+++ b/service/java/com/android/server/wifi/ScanResultMatchInfo.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 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.WifiConfiguration;
+
+import com.android.server.wifi.util.ScanResultUtil;
+
+import java.util.Objects;
+
+/**
+ * Class to store the info needed to match a scan result to the provided network configuration.
+ */
+public class ScanResultMatchInfo {
+    public static final int NETWORK_TYPE_OPEN = 0;
+    public static final int NETWORK_TYPE_WEP = 1;
+    public static final int NETWORK_TYPE_PSK = 2;
+    public static final int NETWORK_TYPE_EAP = 3;
+
+    /**
+     * SSID of the network.
+     */
+    public String networkSsid;
+    /**
+     * Security Type of the network.
+     */
+    public int networkType;
+
+    /**
+     * Get the ScanResultMatchInfo for the given WifiConfiguration
+     */
+    public static ScanResultMatchInfo fromWifiConfiguration(WifiConfiguration config) {
+        ScanResultMatchInfo info = new ScanResultMatchInfo();
+        info.networkSsid = config.SSID;
+        if (WifiConfigurationUtil.isConfigForPskNetwork(config)) {
+            info.networkType = NETWORK_TYPE_PSK;
+        } else if (WifiConfigurationUtil.isConfigForEapNetwork(config)) {
+            info.networkType = NETWORK_TYPE_EAP;
+        } else if (WifiConfigurationUtil.isConfigForWepNetwork(config)) {
+            info.networkType = NETWORK_TYPE_WEP;
+        } else if (WifiConfigurationUtil.isConfigForOpenNetwork(config)) {
+            info.networkType = NETWORK_TYPE_OPEN;
+        } else {
+            throw new IllegalArgumentException("Invalid WifiConfiguration: " + config);
+        }
+        return info;
+    }
+
+    /**
+     * Get the ScanResultMatchInfo for the given ScanResult
+     */
+    public static ScanResultMatchInfo fromScanResult(ScanResult scanResult) {
+        ScanResultMatchInfo info = new ScanResultMatchInfo();
+        // Scan result ssid's are not quoted, hence add quotes.
+        // TODO: This matching algo works only if the scan result contains a string SSID.
+        // However, according to our public documentation ths {@link WifiConfiguration#SSID} can
+        // either have a hex string or quoted ASCII string SSID.
+        info.networkSsid = ScanResultUtil.createQuotedSSID(scanResult.SSID);
+        if (ScanResultUtil.isScanResultForPskNetwork(scanResult)) {
+            info.networkType = NETWORK_TYPE_PSK;
+        } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) {
+            info.networkType = NETWORK_TYPE_EAP;
+        } else if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) {
+            info.networkType = NETWORK_TYPE_WEP;
+        } else if (ScanResultUtil.isScanResultForOpenNetwork(scanResult)) {
+            info.networkType = NETWORK_TYPE_OPEN;
+        } else {
+            throw new IllegalArgumentException("Invalid ScanResult: " + scanResult);
+        }
+        return info;
+    }
+
+    @Override
+    public boolean equals(Object otherObj) {
+        if (this == otherObj) {
+            return true;
+        } else if (!(otherObj instanceof ScanResultMatchInfo)) {
+            return false;
+        }
+        ScanResultMatchInfo other = (ScanResultMatchInfo) otherObj;
+        return Objects.equals(networkSsid, other.networkSsid)
+                && networkType == other.networkType;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(networkSsid, networkType);
+    }
+
+    @Override
+    public String toString() {
+        return "ScanResultMatchInfo: " + networkSsid + ", type: " + networkType;
+    }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/ScanResultMatchInfoTest.java b/tests/wifitests/src/com/android/server/wifi/ScanResultMatchInfoTest.java
new file mode 100644
index 0000000..e2905a6
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/ScanResultMatchInfoTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.*;
+
+import android.net.wifi.WifiConfiguration;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.ScanResultMatchInfoTest}.
+ */
+@SmallTest
+public class ScanResultMatchInfoTest {
+    /**
+     * Tests that equivalent ScanResultMatchInfo objects are created for WifiConfigurations and
+     * their associated ScanResult
+     */
+    @Test
+    public void testScanResultMatchesWifiConfiguration() {
+        WifiConfiguration conf =
+                WifiConfigurationTestUtil.createPskNetwork("\"PrettyFlyForAWifi\"");
+        ScanDetail scan = createScanDetailForNetwork(conf, "AA:AA:AA:AA:AA:AA");
+        assertEquals(ScanResultMatchInfo.fromWifiConfiguration(conf),
+                ScanResultMatchInfo.fromScanResult(scan.getScanResult()));
+
+        conf = WifiConfigurationTestUtil.createOpenNetwork("\"WIFIght the inevitable\"");
+        scan = createScanDetailForNetwork(conf, "BB:BB:BB:BB:BB:BB");
+        assertEquals(ScanResultMatchInfo.fromWifiConfiguration(conf),
+                ScanResultMatchInfo.fromScanResult(scan.getScanResult()));
+    }
+
+    /**
+     * Tests that multiple ScanResults with different BSSIDs will produce equivalent
+     * ScanResultMatchInfo objects to their associated WifiConfiguration
+     */
+    @Test
+    public void testDifferentBssidScanResultsMatch() {
+        WifiConfiguration conf =
+                WifiConfigurationTestUtil.createPskNetwork("\"PrettyFlyForAWifi-5G\"");
+        ScanDetail scan1 = createScanDetailForNetwork(conf, "AA:AA:AA:AA:AA:AA");
+        ScanDetail scan2 = createScanDetailForNetwork(conf, "BB:BB:BB:BB:BB:BB");
+        assertFalse(scan1.getScanResult().BSSID.equals(scan2.getScanResult().BSSID));
+        assertEquals(ScanResultMatchInfo.fromScanResult(scan1.getScanResult()),
+                ScanResultMatchInfo.fromScanResult(scan2.getScanResult()));
+    }
+
+    /**
+     * Tests that ScanResultMatchInfo objects created for different SSIDs or security types are not
+     * equivalent
+     */
+    @Test
+    public void testDifferentNetworkScanResultsDontMatch() {
+        WifiConfiguration psk =
+                WifiConfigurationTestUtil.createPskNetwork("\"Series Of Tubes\"");
+        WifiConfiguration open1 =
+                WifiConfigurationTestUtil.createOpenNetwork("\"Series Of Tubes\"");
+        WifiConfiguration open2 =
+                WifiConfigurationTestUtil.createOpenNetwork("\"Mom, Click Here For Internet\"");
+        ScanDetail scanOpen1 = createScanDetailForNetwork(open1, "AA:AA:AA:AA:AA:AA");
+        ScanDetail scanOpen2 = createScanDetailForNetwork(open2, "BB:BB:BB:BB:BB:BB");
+        ScanDetail scanPsk =   createScanDetailForNetwork(psk,   "CC:CC:CC:CC:CC:CC");
+        assertTrue(ScanResultMatchInfo.fromScanResult(scanOpen1.getScanResult())
+                != ScanResultMatchInfo.fromScanResult(scanOpen2.getScanResult()));
+        assertTrue(ScanResultMatchInfo.fromScanResult(scanOpen1.getScanResult())
+                != ScanResultMatchInfo.fromScanResult(scanPsk.getScanResult()));
+    }
+
+    /**
+     * Creates a scan detail corresponding to the provided network and given BSSID
+     */
+    private ScanDetail createScanDetailForNetwork(
+            WifiConfiguration configuration, String bssid) {
+        return WifiConfigurationTestUtil.createScanDetailForNetwork(configuration, bssid, -40,
+                2402, 0, 0);
+    }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
index 62a68d4..16c9f30 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
@@ -225,7 +225,11 @@
      * use a static index to avoid duplicate configurations.
      */
     public static WifiConfiguration createOpenNetwork() {
-        return generateWifiConfig(TEST_NETWORK_ID, TEST_UID, createNewSSID(), true, true, null,
+        return createOpenNetwork(createNewSSID());
+    }
+
+    public static WifiConfiguration createOpenNetwork(String ssid) {
+        return generateWifiConfig(TEST_NETWORK_ID, TEST_UID, ssid, true, true, null,
                 null, SECURITY_NONE);
     }