diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
new file mode 100644
index 0000000000000..5850feee004ad
--- /dev/null
+++ b/wifi/tests/Android.mk
@@ -0,0 +1,61 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Make test APK
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+# This list is generated from the java source files in this module
+# The list is a comma separated list of class names with * matching zero or more characters.
+# Example:
+# Input files: src/com/android/server/wifi/Test.java src/com/android/server/wifi/AnotherTest.java
+# Generated exclude list: com.android.server.wifi.Test*,com.android.server.wifi.AnotherTest*
+
+# Filter all src files to just java files
+local_java_files := $(filter %.java,$(LOCAL_SRC_FILES))
+# Transform java file names into full class names.
+# This only works if the class name matches the file name and the directory structure
+# matches the package.
+local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
+# Utility variables to allow replacing a space with a comma
+comma:= ,
+empty:=
+space:= $(empty) $(empty)
+# Convert class name list to jacoco exclude list
+# This appends a * to all classes and replace the space separators with commas.
+# These patterns will match all classes in this module and their inner classes.
+jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
+
+jacoco_include := android.net.wifi.*
+
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include)
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ mockito-target-minus-junit4 \
+ frameworks-base-testutils \
+
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner \
+
+LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
+
+include $(BUILD_PACKAGE)
diff --git a/wifi/tests/AndroidManifest.xml b/wifi/tests/AndroidManifest.xml
new file mode 100644
index 0000000000000..4eaca2b98a1d7
--- /dev/null
+++ b/wifi/tests/AndroidManifest.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wifi/tests/README.md b/wifi/tests/README.md
new file mode 100644
index 0000000000000..b418abd5e46b5
--- /dev/null
+++ b/wifi/tests/README.md
@@ -0,0 +1,50 @@
+# Wifi Unit Tests
+This package contains unit tests for the android wifi framework APIs based on the
+[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html).
+The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/)
+libraries.
+
+## Running Tests
+The easiest way to run tests is simply run
+
+```
+frameworks/base/wifi/tests/runtests.sh
+```
+
+`runtests.sh` will build the test project and all of its dependencies and push the APK to the
+connected device. It will then run the tests on the device.
+
+To pick up changes in framework/base, you will need to:
+1. rebuild the framework library 'make -j32'
+2. sync over the updated library to the device 'adb sync'
+3. restart framework on the device 'adb shell stop' then 'adb shell start'
+
+To enable syncing data to the device for first time after clean reflash:
+1. adb disable-verity
+2. adb reboot
+3. adb remount
+
+See below for a few example of options to limit which tests are run.
+See the
+[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html)
+for more details on the supported options.
+
+```
+runtests.sh -e package android.net.wifi
+runtests.sh -e class android.net.wifi.WifiScannerTest
+```
+
+If you manually build and push the test APK to the device you can run tests using
+
+```
+adb shell am instrument -w 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
+```
+
+## Adding Tests
+Tests can be added by adding classes to the src directory. JUnit4 style test cases can
+be written by simply annotating test methods with `org.junit.Test`.
+
+## Debugging Tests
+If you are trying to debug why tests are not doing what you expected, you can add android log
+statements and use logcat to view them. The beginning and end of every tests is automatically logged
+with the tag `TestRunner`.
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
new file mode 100755
index 0000000000000..ebcc2a2f34a2f
--- /dev/null
+++ b/wifi/tests/runtests.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+ echo "You need to source and lunch before you can use this script"
+ exit 1
+fi
+
+echo "Running tests"
+
+set -e # fail early
+
+echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests"
+# NOTE Don't actually run the command above since this shell doesn't inherit functions from the
+# caller.
+make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-wifi-tests
+
+set -x # print commands
+
+adb root
+adb wait-for-device
+
+adb install -r -g "$OUT/data/app/FrameworksWifiApiTests/FrameworksWifiApiTests.apk"
+
+adb shell am instrument -w "$@" 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
diff --git a/wifi/tests/src/android/net/wifi/FakeKeys.java b/wifi/tests/src/android/net/wifi/FakeKeys.java
new file mode 100644
index 0000000000000..0c730705b0394
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/FakeKeys.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 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 android.net.wifi;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+/**
+ * A class containing test certificates.
+ */
+public class FakeKeys {
+ private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDKDCCAhCgAwIBAgIJAILlFdwzLVurMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" +
+ "BAMTB0VBUCBDQTEwHhcNMTYwMTEyMTE1MDE1WhcNMjYwMTA5MTE1MDE1WjASMRAw\n" +
+ "DgYDVQQDEwdFQVAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+ "znAPUz26Msae4ws43czR41/J2QtrSIZUKmVUsVumDbYHrPNvTXKSMXAcewORDQYX\n" +
+ "RqvHvpn8CscB1+oGXZvHwxj4zV0WKoK2zeXkau3vcyl3HIKupJfq2TEACefVjj0t\n" +
+ "JW+X35PGWp9/H5zIUNVNVjS7Ums84IvKhRB8512PB9UyHagXYVX5GWpAcVpyfrlR\n" +
+ "FI9Qdhh+Pbk0uyktdbf/CdfgHOoebrTtwRljM0oDtX+2Cv6j0wBK7hD8pPvf1+uy\n" +
+ "GzczigAU/4Kw7eZqydf9B+5RupR+IZipX41xEiIrKRwqi517WWzXcjaG2cNbf451\n" +
+ "xpH5PnV3i1tq04jMGQUzFwIDAQABo4GAMH4wHQYDVR0OBBYEFIwX4vs8BiBcScod\n" +
+ "5noZHRM8E4+iMEIGA1UdIwQ7MDmAFIwX4vs8BiBcScod5noZHRM8E4+ioRakFDAS\n" +
+ "MRAwDgYDVQQDEwdFQVAgQ0ExggkAguUV3DMtW6swDAYDVR0TBAUwAwEB/zALBgNV\n" +
+ "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFfQqOTA7Rv7K+luQ7pnas4BYwHE\n" +
+ "9GEP/uohv6KOy0TGQFbrRTjFoLVNB9BZ1ymMDZ0/TIwIUc7wi7a8t5mEqYH153wW\n" +
+ "aWooiSjyLLhuI4sNrNCOtisdBq2r2MFXt6h0mAQYOPv8R8K7/fgSxGFqzhyNmmVL\n" +
+ "1qBJldx34SpwsTALQVPb4hGwJzZfr1PcpEQx6xMnTl8xEWZE3Ms99uaUxbQqIwRu\n" +
+ "LgAOkNCmY2m89VhzaHJ1uV85AdM/tD+Ysmlnnjt9LRCejbBipjIGjOXrg1JP+lxV\n" +
+ "muM4vH+P/mlmxsPPz0d65b+EGmJZpoLkO/tdNNvCYzjJpTEWpEsO6NMhKYo=\n" +
+ "-----END CERTIFICATE-----\n";
+ public static final X509Certificate CA_CERT0 = loadCertificate(CA_CERT0_STRING);
+
+ private static final String CA_CERT1_STRING = "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDKDCCAhCgAwIBAgIJAOM5SzKO2pzCMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" +
+ "BAMTB0VBUCBDQTAwHhcNMTYwMTEyMDAxMDQ3WhcNMjYwMTA5MDAxMDQ3WjASMRAw\n" +
+ "DgYDVQQDEwdFQVAgQ0EwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+ "89ug+IEKVQXnJGKg5g4uVHg6J/8iRUxR5k2eH5o03hrJNMfN2D+cBe/wCiZcnWbI\n" +
+ "GbGZACWm2nQth2wy9Zgm2LOd3b4ocrHYls3XLq6Qb5Dd7a0JKU7pdGufiNVEkrmF\n" +
+ "EB+N64wgwH4COTvCiN4erp5kyJwkfqAl2xLkZo0C464c9XoyQOXbmYD9A8v10wZu\n" +
+ "jyNsEo7Nr2USyw+qhjWSbFbEirP77Tvx+7pJQJwdtk1V9Tn73T2dGF2WHYejei9S\n" +
+ "mcWpdIUqsu9etYH+zDmtu7I1xlkwiaVsNr2+D+qaCJyOYqrDTKVNK5nmbBPXDWZc\n" +
+ "NoDbTOoqquX7xONpq9M6jQIDAQABo4GAMH4wHQYDVR0OBBYEFAZ3A2S4qJZZwuNY\n" +
+ "wkJ6mAdc0gVdMEIGA1UdIwQ7MDmAFAZ3A2S4qJZZwuNYwkJ6mAdc0gVdoRakFDAS\n" +
+ "MRAwDgYDVQQDEwdFQVAgQ0EwggkA4zlLMo7anMIwDAYDVR0TBAUwAwEB/zALBgNV\n" +
+ "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHmdMwEhtys4d0E+t7owBmoVR+lU\n" +
+ "hMCcRtWs8YKX5WIM2kTweT0h/O1xwE1mWmRv/IbDAEb8od4BjAQLhIcolStr2JaO\n" +
+ "9ZzyxjOnNzqeErh/1DHDbb/moPpqfeJ8YiEz7nH/YU56Q8iCPO7TsgS0sNNE7PfN\n" +
+ "IUsBW0yHRgpQ4OxWmiZG2YZWiECRzAC0ecPzo59N5iH4vLQIMTMYquiDeMPQnn1e\n" +
+ "NDGxG8gCtDKIaS6tMg3a28MvWB094pr2ETou8O1C8Ji0Y4hE8QJmSdT7I4+GZjgW\n" +
+ "g94DZ5RiL7sdp3vC48CXOmeT61YBIvhGUsE1rPhXqkpqQ3Z3C4TFF0jXZZc=\n" +
+ "-----END CERTIFICATE-----\n";
+ public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING);
+
+
+ private static X509Certificate loadCertificate(String blob) {
+ try {
+ final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ InputStream stream = new ByteArrayInputStream(blob.getBytes(StandardCharsets.UTF_8));
+
+ return (X509Certificate) certFactory.generateCertificate(stream);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
new file mode 100644
index 0000000000000..0d964b7c92d7f
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2016 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 android.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+
+import android.net.wifi.WifiEnterpriseConfig.Eap;
+import android.net.wifi.WifiEnterpriseConfig.Phase2;
+import android.os.Parcel;
+import android.security.Credentials;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.cert.X509Certificate;
+
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiEnterpriseConfig}.
+ */
+@SmallTest
+public class WifiEnterpriseConfigTest {
+ // Maintain a ground truth of the keystore uri prefix which is expected by wpa_supplicant.
+ public static final String KEYSTORE_URI = "keystore://";
+ public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
+ public static final String KEYSTORES_URI = "keystores://";
+
+ private WifiEnterpriseConfig mEnterpriseConfig;
+
+ @Before
+ public void setUp() throws Exception {
+ mEnterpriseConfig = new WifiEnterpriseConfig();
+ }
+
+ @Test
+ public void testGetEmptyCaCertificate() {
+ // A newly-constructed WifiEnterpriseConfig object should have no CA certificate.
+ assertNull(mEnterpriseConfig.getCaCertificate());
+ assertNull(mEnterpriseConfig.getCaCertificates());
+ // Setting CA certificate to null explicitly.
+ mEnterpriseConfig.setCaCertificate(null);
+ assertNull(mEnterpriseConfig.getCaCertificate());
+ // Setting CA certificate to null using setCaCertificates().
+ mEnterpriseConfig.setCaCertificates(null);
+ assertNull(mEnterpriseConfig.getCaCertificates());
+ // Setting CA certificate to zero-length array.
+ mEnterpriseConfig.setCaCertificates(new X509Certificate[0]);
+ assertNull(mEnterpriseConfig.getCaCertificates());
+ }
+
+ @Test
+ public void testSetGetSingleCaCertificate() {
+ X509Certificate cert0 = FakeKeys.CA_CERT0;
+ mEnterpriseConfig.setCaCertificate(cert0);
+ assertEquals(mEnterpriseConfig.getCaCertificate(), cert0);
+ }
+
+ @Test
+ public void testSetGetMultipleCaCertificates() {
+ X509Certificate cert0 = FakeKeys.CA_CERT0;
+ X509Certificate cert1 = FakeKeys.CA_CERT1;
+ mEnterpriseConfig.setCaCertificates(new X509Certificate[] {cert0, cert1});
+ X509Certificate[] result = mEnterpriseConfig.getCaCertificates();
+ assertEquals(result.length, 2);
+ assertTrue(result[0] == cert0 && result[1] == cert1);
+ }
+
+ @Test
+ public void testSaveSingleCaCertificateAlias() {
+ final String alias = "single_alias 0";
+ mEnterpriseConfig.setCaCertificateAliases(new String[] {alias});
+ assertEquals(getCaCertField(), CA_CERT_PREFIX + alias);
+ }
+
+ @Test
+ public void testLoadSingleCaCertificateAlias() {
+ final String alias = "single_alias 1";
+ setCaCertField(CA_CERT_PREFIX + alias);
+ String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
+ assertEquals(aliases.length, 1);
+ assertEquals(aliases[0], alias);
+ }
+
+ @Test
+ public void testSaveMultipleCaCertificates() {
+ final String alias0 = "single_alias 0";
+ final String alias1 = "single_alias 1";
+ mEnterpriseConfig.setCaCertificateAliases(new String[] {alias0, alias1});
+ assertEquals(getCaCertField(), String.format("%s%s %s",
+ KEYSTORES_URI,
+ WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
+ WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
+ }
+
+ @Test
+ public void testLoadMultipleCaCertificates() {
+ final String alias0 = "single_alias 0";
+ final String alias1 = "single_alias 1";
+ setCaCertField(String.format("%s%s %s",
+ KEYSTORES_URI,
+ WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
+ WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
+ String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
+ assertEquals(aliases.length, 2);
+ assertEquals(aliases[0], alias0);
+ assertEquals(aliases[1], alias1);
+ }
+
+ private String getCaCertField() {
+ return mEnterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY);
+ }
+
+ private void setCaCertField(String value) {
+ mEnterpriseConfig.setFieldValue(WifiEnterpriseConfig.CA_CERT_KEY, value);
+ }
+
+ // Retrieves the value for a specific key supplied to wpa_supplicant.
+ private class SupplicantConfigExtractor implements WifiEnterpriseConfig.SupplicantSaver {
+ private String mValue = null;
+ private String mKey;
+
+ SupplicantConfigExtractor(String key) {
+ mKey = key;
+ }
+
+ @Override
+ public boolean saveValue(String key, String value) {
+ if (key.equals(mKey)) {
+ mValue = value;
+ }
+ return true;
+ }
+
+ public String getValue() {
+ return mValue;
+ }
+ }
+
+ private String getSupplicantEapMethod() {
+ SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
+ WifiEnterpriseConfig.EAP_KEY);
+ mEnterpriseConfig.saveToSupplicant(entryExtractor);
+ return entryExtractor.getValue();
+ }
+
+ private String getSupplicantPhase2Method() {
+ SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
+ WifiEnterpriseConfig.PHASE2_KEY);
+ mEnterpriseConfig.saveToSupplicant(entryExtractor);
+ return entryExtractor.getValue();
+ }
+
+ /** Verifies the default value for EAP outer and inner methods */
+ @Test
+ public void eapInnerDefault() {
+ assertEquals(null, getSupplicantEapMethod());
+ assertEquals(null, getSupplicantPhase2Method());
+ }
+
+ /** Verifies that the EAP inner method is reset when we switch to TLS */
+ @Test
+ public void eapPhase2MethodForTls() {
+ // Initially select an EAP method that supports an phase2.
+ mEnterpriseConfig.setEapMethod(Eap.PEAP);
+ mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+ assertEquals("PEAP", getSupplicantEapMethod());
+ assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+ // Change the EAP method to another type which supports a phase2.
+ mEnterpriseConfig.setEapMethod(Eap.TTLS);
+ assertEquals("TTLS", getSupplicantEapMethod());
+ assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+ // Change the EAP method to TLS which does not support a phase2.
+ mEnterpriseConfig.setEapMethod(Eap.TLS);
+ assertEquals(null, getSupplicantPhase2Method());
+ }
+
+ /** Verfies that the EAP inner method is reset when we switch phase2 to NONE */
+ @Test
+ public void eapPhase2None() {
+ // Initially select an EAP method that supports an phase2.
+ mEnterpriseConfig.setEapMethod(Eap.PEAP);
+ mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+ assertEquals("PEAP", getSupplicantEapMethod());
+ assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+ // Change the phase2 method to NONE and ensure the value is cleared.
+ mEnterpriseConfig.setPhase2Method(Phase2.NONE);
+ assertEquals(null, getSupplicantPhase2Method());
+ }
+
+ /** Verfies that the correct "autheap" parameter is supplied for TTLS/GTC. */
+ @Test
+ public void peapGtcToTtls() {
+ mEnterpriseConfig.setEapMethod(Eap.PEAP);
+ mEnterpriseConfig.setPhase2Method(Phase2.GTC);
+ assertEquals("PEAP", getSupplicantEapMethod());
+ assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
+
+ mEnterpriseConfig.setEapMethod(Eap.TTLS);
+ assertEquals("TTLS", getSupplicantEapMethod());
+ assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+ }
+
+ /** Verfies that the correct "auth" parameter is supplied for PEAP/GTC. */
+ @Test
+ public void ttlsGtcToPeap() {
+ mEnterpriseConfig.setEapMethod(Eap.TTLS);
+ mEnterpriseConfig.setPhase2Method(Phase2.GTC);
+ assertEquals("TTLS", getSupplicantEapMethod());
+ assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+
+ mEnterpriseConfig.setEapMethod(Eap.PEAP);
+ assertEquals("PEAP", getSupplicantEapMethod());
+ assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
+ }
+
+ /** Verfies that the copy constructor preseves the inner method information. */
+ @Test
+ public void copyConstructor() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(Eap.TTLS);
+ enterpriseConfig.setPhase2Method(Phase2.GTC);
+ mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+ assertEquals("TTLS", getSupplicantEapMethod());
+ assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+ }
+
+ /** Verfies that parceling a WifiEnterpriseConfig preseves method information. */
+ @Test
+ public void parcelConstructor() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(Eap.TTLS);
+ enterpriseConfig.setPhase2Method(Phase2.GTC);
+ Parcel parcel = Parcel.obtain();
+ enterpriseConfig.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0); // Allow parcel to be read from the beginning.
+ mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
+ assertEquals("TTLS", getSupplicantEapMethod());
+ assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+ }
+
+ /** Verifies proper operation of the getKeyId() method. */
+ @Test
+ public void getKeyId() {
+ assertEquals("NULL", mEnterpriseConfig.getKeyId(null));
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(Eap.TTLS);
+ enterpriseConfig.setPhase2Method(Phase2.GTC);
+ assertEquals("TTLS_GTC", mEnterpriseConfig.getKeyId(enterpriseConfig));
+ mEnterpriseConfig.setEapMethod(Eap.PEAP);
+ mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+ assertEquals("PEAP_MSCHAPV2", mEnterpriseConfig.getKeyId(enterpriseConfig));
+ }
+
+ /** Verifies that passwords are not displayed in toString. */
+ @Test
+ public void passwordNotInToString() {
+ String password = "supersecret";
+ mEnterpriseConfig.setPassword(password);
+ assertFalse(mEnterpriseConfig.toString().contains(password));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
new file mode 100644
index 0000000000000..a829eb933b592
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 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 android.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.validateMockitoUsage;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiScanner.BssidInfo;
+import android.net.wifi.WifiScanner.BssidListener;
+import android.os.Handler;
+import android.os.Message;
+import android.os.test.TestLooper;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.util.test.BidirectionalAsyncChannelServer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiScanner}.
+ */
+@SmallTest
+public class WifiScannerTest {
+ @Mock
+ private Context mContext;
+ @Mock
+ private IWifiScanner mService;
+ @Mock
+ private BssidListener mBssidListener;
+
+ private WifiScanner mWifiScanner;
+ private TestLooper mLooper;
+ private Handler mHandler;
+
+ /**
+ * Setup before tests.
+ */
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mLooper = new TestLooper();
+ mHandler = mock(Handler.class);
+ BidirectionalAsyncChannelServer server = new BidirectionalAsyncChannelServer(
+ mContext, mLooper.getLooper(), mHandler);
+ when(mService.getMessenger()).thenReturn(server.getMessenger());
+ mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
+ mLooper.dispatchAll();
+ }
+
+ /**
+ * Clean up after tests.
+ */
+ @After
+ public void cleanup() {
+ validateMockitoUsage();
+ }
+
+ private void verifySetHotlistMessage(Handler handler) {
+ ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(handler, atLeastOnce()).handleMessage(messageCaptor.capture());
+ assertEquals("message.what is not CMD_SET_HOTLIST",
+ WifiScanner.CMD_SET_HOTLIST,
+ messageCaptor.getValue().what);
+ }
+
+ /**
+ * Test duplicate listeners for bssid tracking.
+ */
+ @Test
+ public void testStartTrackingBssidsDuplicateListeners() throws Exception {
+ BssidInfo[] bssids = new BssidInfo[] {
+ new BssidInfo()
+ };
+
+ // First start tracking succeeds.
+ mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener);
+ mLooper.dispatchAll();
+ verifySetHotlistMessage(mHandler);
+
+ // Second start tracking should fail.
+ mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener);
+ mLooper.dispatchAll();
+ verify(mBssidListener).onFailure(eq(WifiScanner.REASON_DUPLICATE_REQEUST), anyString());
+ }
+}