Merge "WifiMigrationTest: Remove all usage of WifiMigration.loadFromStore" into rvc-dev
diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java
index 63fa1dd..3e9fef4 100644
--- a/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java
+++ b/tests/cts/net/src/android/net/wifi/cts/WifiFeature.java
@@ -20,12 +20,12 @@
 import android.content.pm.PackageManager;
 
 public class WifiFeature {
-    static boolean isWifiSupported(Context context) {
+    public static boolean isWifiSupported(Context context) {
         PackageManager packageManager = context.getPackageManager();
         return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
     }
 
-    static boolean isP2pSupported(Context context) {
+    public static boolean isP2pSupported(Context context) {
         PackageManager packageManager = context.getPackageManager();
         return packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT);
     }
diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java
index 12efb00..96e1caa 100644
--- a/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java
+++ b/tests/cts/net/src/android/net/wifi/cts/WifiHotspot2Test.java
@@ -23,11 +23,18 @@
 import android.net.wifi.hotspot2.pps.HomeSp;
 import android.test.AndroidTestCase;
 
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
 
 public class WifiHotspot2Test extends AndroidTestCase {
+    static final int SIM_CREDENTIAL = 0;
+    static final int USER_CREDENTIAL = 1;
+    static final int CERT_CREDENTIAL = 2;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -44,7 +51,7 @@
 
     /**
      * Tests {@link PasspointConfiguration#getMeteredOverride()} method.
-     *
+     * <p>
      * Test default value
      */
     public void testGetMeteredOverride() throws Exception {
@@ -58,7 +65,7 @@
 
     /**
      * Tests {@link PasspointConfiguration#getSubscriptionExpirationTimeMillis()} method.
-     *
+     * <p>
      * Test default value
      */
     public void testGetSubscriptionExpirationTimeMillis() throws Exception {
@@ -73,7 +80,7 @@
 
     /**
      * Tests {@link PasspointConfiguration#getUniqueId()} method.
-     *
+     * <p>
      * Test unique identifier is not null
      */
     public void testGetUniqueId() throws Exception {
@@ -81,13 +88,32 @@
             // skip the test if WiFi is not supported
             return;
         }
-        PasspointConfiguration passpointConfiguration = createConfig();
-        assertNotNull(passpointConfiguration.getUniqueId());
+
+        // Create a configuration and make sure the unique ID is not null
+        PasspointConfiguration passpointConfiguration1 = createConfig(SIM_CREDENTIAL, "123456*",
+                18 /* EAP_SIM */);
+        String uniqueId1 = passpointConfiguration1.getUniqueId();
+        assertNotNull(uniqueId1);
+
+        // Create another configuration and make sure the unique ID is not null
+        PasspointConfiguration passpointConfiguration2 = createConfig(SIM_CREDENTIAL, "567890*",
+                23 /* EAP_AKA */);
+        String uniqueId2 = passpointConfiguration2.getUniqueId();
+        assertNotNull(uniqueId2);
+
+        // Make sure the IDs are not equal
+        assertFalse(uniqueId1.equals(uniqueId2));
+
+        passpointConfiguration2 = createConfig(USER_CREDENTIAL);
+        assertFalse(uniqueId1.equals(passpointConfiguration2.getUniqueId()));
+
+        passpointConfiguration2 = createConfig(CERT_CREDENTIAL);
+        assertFalse(uniqueId1.equals(passpointConfiguration2.getUniqueId()));
     }
 
     /**
      * Tests {@link PasspointConfiguration#isAutojoinEnabled()} method.
-     *
+     * <p>
      * Test default value
      */
     public void testIsAutojoinEnabled() throws Exception {
@@ -101,7 +127,7 @@
 
     /**
      * Tests {@link PasspointConfiguration#isMacRandomizationEnabled()} method.
-     *
+     * <p>
      * Test default value
      */
     public void testIsMacRandomizationEnabled() throws Exception {
@@ -115,7 +141,7 @@
 
     /**
      * Tests {@link PasspointConfiguration#isOsuProvisioned()} method.
-     *
+     * <p>
      * Test default value
      */
     public void testIsOsuProvisioned() throws Exception {
@@ -123,13 +149,13 @@
             // skip the test if WiFi is not supported
             return;
         }
-        PasspointConfiguration passpointConfiguration = createConfig();
+        PasspointConfiguration passpointConfiguration = createConfig(USER_CREDENTIAL);
         assertFalse(passpointConfiguration.isOsuProvisioned());
     }
 
     /**
      * Tests {@link PasspointConfiguration#PasspointConfiguration(PasspointConfiguration)} method.
-     *
+     * <p>
      * Test the PasspointConfiguration copy constructor
      */
     public void testPasspointConfigurationCopyConstructor() throws Exception {
@@ -137,7 +163,7 @@
             // skip the test if WiFi is not supported
             return;
         }
-        PasspointConfiguration passpointConfiguration = createConfig();
+        PasspointConfiguration passpointConfiguration = createConfig(USER_CREDENTIAL);
         PasspointConfiguration copyOfPasspointConfiguration =
                 new PasspointConfiguration(passpointConfiguration);
         assertEquals(passpointConfiguration, copyOfPasspointConfiguration);
@@ -145,7 +171,7 @@
 
     /**
      * Tests {@link HomeSp#HomeSp(HomeSp)} method.
-     *
+     * <p>
      * Test the HomeSp copy constructor
      */
     public void testHomeSpCopyConstructor() throws Exception {
@@ -160,7 +186,7 @@
 
     /**
      * Tests {@link Credential#Credential(Credential)} method.
-     *
+     * <p>
      * Test the Credential copy constructor
      */
     public void testCredentialCopyConstructor() throws Exception {
@@ -168,14 +194,14 @@
             // skip the test if WiFi is not supported
             return;
         }
-        Credential credential = createCredential();
+        Credential credential = createCredentialWithSimCredential("123456*", 18 /* EAP_SIM */);
         Credential copyOfCredential = new Credential(credential);
         assertEquals(copyOfCredential, credential);
     }
 
     /**
      * Tests {@link Credential.UserCredential#UserCredential(Credential.UserCredential)} method.
-     *
+     * <p>
      * Test the Credential.UserCredential copy constructor
      */
     public void testUserCredentialCopyConstructor() throws Exception {
@@ -195,9 +221,10 @@
     }
 
     /**
-     * Tests {@link Credential.CertificateCredential#CertificateCredential(Credential.CertificateCredential)}
+     * Tests
+     * {@link Credential.CertificateCredential#CertificateCredential(Credential.CertificateCredential)}
      * method.
-     *
+     * <p>
      * Test the Credential.CertificateCredential copy constructor
      */
     public void testCertCredentialCopyConstructor() throws Exception {
@@ -214,9 +241,8 @@
     }
 
     /**
-     * Tests {@link Credential.SimCredential#SimCredential(Credential.SimCredential)}
-     * method.
-     *
+     * Tests {@link Credential.SimCredential#SimCredential(Credential.SimCredential)} method.
+     * <p>
      * Test the Credential.SimCredential copy constructor
      */
     public void testSimCredentialCopyConstructor() throws Exception {
@@ -234,7 +260,7 @@
 
     /**
      * Tests {@link Credential#getCaCertificate()}  method.
-     *
+     * <p>
      * Test that getting a set certificate produces the same value
      */
     public void testCredentialGetCertificate() throws Exception {
@@ -249,9 +275,9 @@
     }
 
     /**
-     * Tests {@link Credential#getClientCertificateChain()} and
-     * {@link Credential#setCaCertificates(X509Certificate[])} methods.
-     *
+     * Tests {@link Credential#getClientCertificateChain()} and {@link
+     * Credential#setCaCertificates(X509Certificate[])} methods.
+     * <p>
      * Test that getting a set client certificate chain produces the same value
      */
     public void testCredentialClientCertificateChain() throws Exception {
@@ -260,7 +286,7 @@
             return;
         }
         Credential credential = new Credential();
-        X509Certificate[] certificates = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+        X509Certificate[] certificates = new X509Certificate[]{FakeKeys.CLIENT_CERT};
         credential.setClientCertificateChain(certificates);
 
         assertTrue(Arrays.equals(certificates, credential.getClientCertificateChain()));
@@ -268,8 +294,9 @@
 
     /**
      * Tests {@link Credential#getClientPrivateKey()} and
-     * {@link Credential#setClientPrivateKey(PrivateKey)} methods.
-     *
+     * {@link Credential#setClientPrivateKey(PrivateKey)}
+     * methods.
+     * <p>
      * Test that getting a set client private key produces the same value
      */
     public void testCredentialSetGetClientPrivateKey() throws Exception {
@@ -285,8 +312,9 @@
 
     /**
      * Tests {@link Credential#getClientPrivateKey()} and
-     * {@link Credential#setClientPrivateKey(PrivateKey)} methods.
-     *
+     * {@link Credential#setClientPrivateKey(PrivateKey)}
+     * methods.
+     * <p>
      * Test that getting a set client private key produces the same value
      */
     public void testCredentialGetClientPrivateKey() throws Exception {
@@ -300,32 +328,110 @@
         assertEquals(FakeKeys.RSA_KEY1, credential.getClientPrivateKey());
     }
 
-    private static PasspointConfiguration createConfig() {
+    private static PasspointConfiguration createConfig(int type) throws Exception {
+        return createConfig(type, "123456*", 18 /* EAP_SIM */);
+    }
+
+    private static PasspointConfiguration createConfig(int type, String imsi, int eapType)
+            throws Exception {
         PasspointConfiguration config = new PasspointConfiguration();
         config.setHomeSp(createHomeSp());
-        config.setCredential(createCredential());
+        switch (type) {
+            default:
+            case SIM_CREDENTIAL:
+                config.setCredential(
+                        createCredentialWithSimCredential(imsi, eapType));
+                break;
+            case USER_CREDENTIAL:
+                config.setCredential(createCredentialWithUserCredential());
+                break;
+            case CERT_CREDENTIAL:
+                config.setCredential(createCredentialWithCertificateCredential());
+                break;
+        }
+
         return config;
     }
 
+    /**
+     * Helper function for generating HomeSp for testing.
+     *
+     * @return {@link HomeSp}
+     */
     private static HomeSp createHomeSp() {
         HomeSp homeSp = new HomeSp();
         homeSp.setFqdn("test.com");
         homeSp.setFriendlyName("friendly name");
-        homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
+        homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66});
         return homeSp;
     }
 
-    private static Credential createCredential() {
+    /**
+     * Helper function for generating Credential for testing.
+     *
+     * @param userCred               Instance of UserCredential
+     * @param certCred               Instance of CertificateCredential
+     * @param simCred                Instance of SimCredential
+     * @param clientCertificateChain Chain of client certificates
+     * @param clientPrivateKey       Client private key
+     * @param caCerts                CA certificates
+     * @return {@link Credential}
+     */
+    private static Credential createCredential(Credential.UserCredential userCred,
+            Credential.CertificateCredential certCred,
+            Credential.SimCredential simCred,
+            X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey,
+            X509Certificate... caCerts) {
         Credential cred = new Credential();
         cred.setRealm("realm");
-        cred.setUserCredential(null);
-        cred.setCertCredential(null);
-        cred.setSimCredential(new Credential.SimCredential());
-        cred.getSimCredential().setImsi("1234*");
-        cred.getSimCredential().setEapType(18/* EAP_SIM */);
-        cred.setCaCertificate(null);
-        cred.setClientCertificateChain(null);
-        cred.setClientPrivateKey(null);
+        cred.setUserCredential(userCred);
+        cred.setCertCredential(certCred);
+        cred.setSimCredential(simCred);
         return cred;
     }
+
+    /**
+     * Helper function for generating certificate credential for testing.
+     *
+     * @return {@link Credential}
+     */
+    private static Credential createCredentialWithCertificateCredential()
+            throws NoSuchAlgorithmException, CertificateEncodingException {
+        Credential.CertificateCredential certCred = new Credential.CertificateCredential();
+        certCred.setCertType("x509v3");
+        certCred.setCertSha256Fingerprint(
+                MessageDigest.getInstance("SHA-256").digest(
+                        FakeKeys.CLIENT_CERT.getEncoded()));
+        return createCredential(null, certCred, null, new X509Certificate[]{
+                        FakeKeys.CLIENT_CERT},
+                FakeKeys.RSA_KEY1, FakeKeys.CA_CERT0,
+                FakeKeys.CA_CERT1);
+    }
+
+    /**
+     * Helper function for generating SIM credential for testing.
+     *
+     * @return {@link Credential}
+     */
+    private static Credential createCredentialWithSimCredential(String imsi, int eapType) {
+        Credential.SimCredential simCred = new Credential.SimCredential();
+        simCred.setImsi(imsi);
+        simCred.setEapType(eapType);
+        return createCredential(null, null, simCred, null, null, (X509Certificate[]) null);
+    }
+
+    /**
+     * Helper function for generating user credential for testing.
+     *
+     * @return {@link Credential}
+     */
+    private static Credential createCredentialWithUserCredential() {
+        Credential.UserCredential userCred = new Credential.UserCredential();
+        userCred.setUsername("username");
+        userCred.setPassword("password");
+        userCred.setEapType(21 /* EAP_TTLS */);
+        userCred.setNonEapInnerMethod("MS-CHAP");
+        return createCredential(userCred, null, null, null, null,
+                FakeKeys.CA_CERT0);
+    }
 }
diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
index 2368d1b..51a4f32 100644
--- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -40,8 +40,12 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
+import android.net.TetheringManager;
 import android.net.wifi.ScanResult;
+import android.net.wifi.SoftApCapability;
 import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.SoftApInfo;
+import android.net.wifi.WifiClient;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -49,6 +53,8 @@
 import android.net.wifi.WifiNetworkConnectionStatistics;
 import android.net.wifi.hotspot2.ConfigParser;
 import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.pps.Credential;
+import android.net.wifi.hotspot2.pps.HomeSp;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -74,6 +80,7 @@
 import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -92,6 +99,7 @@
 
     private WifiManager mWifiManager;
     private ConnectivityManager mConnectivityManager;
+    private TetheringManager mTetheringManager;
     private WifiLock mWifiLock;
     private static MySync mMySync;
     private List<ScanResult> mScanResults = null;
@@ -99,6 +107,7 @@
     private final Object mLock = new Object();
     private UiDevice mUiDevice;
     private boolean mWasVerboseLoggingEnabled;
+    private SoftApConfiguration mOriginalSoftApConfig = null;
 
     // Please refer to WifiManager
     private static final int MIN_RSSI = -100;
@@ -201,7 +210,9 @@
         mContext.registerReceiver(mReceiver, mIntentFilter);
         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
         mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
+        mTetheringManager = getContext().getSystemService(TetheringManager.class);
         assertNotNull(mWifiManager);
+        assertNotNull(mTetheringManager);
 
         // turn on verbose logging for tests
         mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions(
@@ -224,6 +235,10 @@
         List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
                 mWifiManager::getConfiguredNetworks);
         assertFalse("Need at least one saved network", savedNetworks.isEmpty());
+
+        // Get original config for restore
+        mOriginalSoftApConfig = ShellIdentityUtils.invokeWithShellPermissions(
+                mWifiManager::getSoftApConfiguration);
     }
 
     @Override
@@ -239,6 +254,9 @@
         mContext.unregisterReceiver(mReceiver);
         ShellIdentityUtils.invokeWithShellPermissions(
                 () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled));
+        // restore original softap config
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.setSoftApConfiguration(mOriginalSoftApConfig));
         Thread.sleep(DURATION);
         super.tearDown();
     }
@@ -508,6 +526,140 @@
         }
     }
 
+    public class TestSoftApCallback implements WifiManager.SoftApCallback {
+        Object softApLock;
+        int currentState;
+        int currentFailureReason;
+        List<WifiClient> currentClientList;
+        SoftApInfo currentSoftApInfo;
+        SoftApCapability currentSoftApCapability;
+        MacAddress lastBlockedClientMacAddress;
+        int lastBlockedClientReason;
+        boolean onStateChangedCalled = false;
+        boolean onSoftapInfoChangedCalled = false;
+        boolean onSoftApCapabilityChangedCalled = false;
+        boolean onConnectedClientCalled = false;
+        boolean onBlockedClientConnectingCalled = false;
+
+        TestSoftApCallback(Object lock) {
+            softApLock = lock;
+        }
+
+        public boolean getOnStateChangedCalled() {
+            synchronized(softApLock) {
+                return onStateChangedCalled;
+            }
+        }
+
+        public boolean getOnSoftapInfoChangedCalled() {
+            synchronized(softApLock) {
+                return onSoftapInfoChangedCalled;
+            }
+        }
+
+        public boolean getOnSoftApCapabilityChangedCalled() {
+            synchronized(softApLock) {
+                return onSoftApCapabilityChangedCalled;
+            }
+        }
+
+        public boolean getOnConnectedClientCalled() {
+            synchronized(softApLock) {
+                return onConnectedClientCalled;
+            }
+        }
+
+        public boolean getOnBlockedClientConnectingCalled() {
+            synchronized(softApLock) {
+                return onBlockedClientConnectingCalled;
+            }
+        }
+
+        public int getCurrentState() {
+            synchronized(softApLock) {
+                return currentState;
+            }
+        }
+
+        public int getCurrentStateFailureReason() {
+            synchronized(softApLock) {
+                return currentFailureReason;
+            }
+        }
+
+        public List<WifiClient> getCurrentClientList() {
+            synchronized(softApLock) {
+                return currentClientList;
+            }
+        }
+
+        public SoftApInfo getCurrentSoftApInfo() {
+            synchronized(softApLock) {
+                return currentSoftApInfo;
+            }
+        }
+
+        public SoftApCapability getCurrentSoftApCapability() {
+            synchronized(softApLock) {
+                return currentSoftApCapability;
+            }
+        }
+
+        public MacAddress getLastBlockedClientMacAddress() {
+            synchronized(softApLock) {
+                return lastBlockedClientMacAddress;
+            }
+        }
+
+        public int getLastBlockedClientReason() {
+            synchronized(softApLock) {
+                return lastBlockedClientReason;
+            }
+        }
+
+        @Override
+        public void onStateChanged(int state, int failureReason) {
+            synchronized(softApLock) {
+                currentState = state;
+                currentFailureReason = failureReason;
+                onStateChangedCalled = true;
+            }
+        }
+
+        @Override
+        public void onConnectedClientsChanged(List<WifiClient> clients) {
+            synchronized(softApLock) {
+                currentClientList = new ArrayList<>(clients);
+                onConnectedClientCalled = true;
+            }
+        }
+
+        @Override
+        public void onInfoChanged(SoftApInfo softApInfo) {
+            synchronized(softApLock) {
+                currentSoftApInfo = softApInfo;
+                onSoftapInfoChangedCalled = true;
+            }
+        }
+
+        @Override
+        public void onCapabilityChanged(SoftApCapability softApCapability) {
+            synchronized(softApLock) {
+                currentSoftApCapability = softApCapability;
+                onSoftApCapabilityChangedCalled = true;
+            }
+        }
+
+        @Override
+        public void onBlockedClientConnecting(WifiClient client, int blockedReason) {
+            synchronized(softApLock) {
+                lastBlockedClientMacAddress = client.getMacAddress();
+                lastBlockedClientReason = blockedReason;
+                onBlockedClientConnectingCalled = true;
+            }
+        }
+    }
+
     private static class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback {
         Object hotspotLock;
         WifiManager.LocalOnlyHotspotReservation reservation = null;
@@ -563,7 +715,10 @@
             }
             // check if we got the callback
             assertTrue(callback.onStartedCalled);
-            assertNotNull(callback.reservation.getSoftApConfiguration());
+
+            SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration();
+            assertNotNull(softApConfig);
+            assertNotNull(softApConfig.toWifiConfiguration());
             if (!hasAutomotiveFeature()) {
                 assertEquals(
                         SoftApConfiguration.BAND_2GHZ,
@@ -1158,6 +1313,178 @@
                 > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP);
     }
 
+    private void verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)
+            throws Exception{
+        // Register callback to get SoftApCapability
+        mWifiManager.registerSoftApCallback(executor, callback);
+        PollingCheck.check(
+                "SoftAp register failed!", 1_000,
+                () -> { executor.runAll();
+                // Verify callback is run on the supplied executor and called
+                return callback.getOnStateChangedCalled() &&
+                callback.getOnSoftapInfoChangedCalled() &&
+                callback.getOnSoftApCapabilityChangedCalled() &&
+                callback.getOnConnectedClientCalled();
+                });
+    }
+
+    private void verifySetGetSoftApConfig(SoftApConfiguration targetConfig) {
+        mWifiManager.setSoftApConfiguration(targetConfig);
+        // Bssid set dodesn't support for tethered hotspot
+        SoftApConfiguration currentConfig = mWifiManager.getSoftApConfiguration();
+        assertNull(currentConfig.getBssid());
+        compareSoftApConfiguration(targetConfig, currentConfig);
+    }
+
+    private void compareSoftApConfiguration(SoftApConfiguration currentConfig,
+        SoftApConfiguration testSoftApConfig) {
+        assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid());
+        assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType());
+        assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase());
+        assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid());
+        assertEquals(currentConfig.getBand(), testSoftApConfig.getBand());
+        assertEquals(currentConfig.getChannel(), testSoftApConfig.getChannel());
+        assertEquals(currentConfig.getMaxNumberOfClients(),
+                testSoftApConfig.getMaxNumberOfClients());
+        assertEquals(currentConfig.isAutoShutdownEnabled(),
+                testSoftApConfig.isAutoShutdownEnabled());
+        assertEquals(currentConfig.getShutdownTimeoutMillis(),
+                testSoftApConfig.getShutdownTimeoutMillis());
+        assertEquals(currentConfig.isClientControlByUserEnabled(),
+                testSoftApConfig.isClientControlByUserEnabled());
+        assertEquals(currentConfig.getAllowedClientList(),
+                testSoftApConfig.getAllowedClientList());
+        assertEquals(currentConfig.getBlockedClientList(),
+                testSoftApConfig.getBlockedClientList());
+    }
+
+    private void turnOffWifiAndTetheredHotspotIfEnabled() throws Exception {
+        if (mWifiManager.isWifiEnabled()) {
+            Log.d(TAG, "Turn off WiFi");
+            mWifiManager.setWifiEnabled(false);
+            PollingCheck.check(
+                "Wifi turn off failed!", 2_000,
+                () -> mWifiManager.isWifiEnabled() == false);
+        }
+        if (mWifiManager.isWifiApEnabled()) {
+            mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+            Log.d(TAG, "Turn off tethered Hotspot");
+            PollingCheck.check(
+                "SoftAp turn off failed!", 2_000,
+                () -> mWifiManager.isWifiApEnabled() == false);
+            mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+        }
+    }
+
+    /**
+     * Verify that the configuration from getSoftApConfiguration is same as the configuration which
+     * set by setSoftApConfiguration. And depends softap capability callback to test different
+     * configuration.
+     * @throws Exception
+     */
+    public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception {
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+            turnOffWifiAndTetheredHotspotIfEnabled();
+            TestExecutor executor = new TestExecutor();
+            TestSoftApCallback callback = new TestSoftApCallback(mLock);
+            verifyRegisterSoftApCallback(executor, callback);
+
+            SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder()
+                    .setSsid(TEST_SSID_UNQUOTED)
+                    .setBssid(TEST_MAC)
+                    .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+                    .setAutoShutdownEnabled(true)
+                    .setShutdownTimeoutMillis(100000)
+                    .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ)
+                    .setHiddenSsid(false);
+
+            // Test SoftApConfiguration set and get
+            verifySetGetSoftApConfig(softApConfigBuilder.build());
+
+            // Test CLIENT_FORCE_DISCONNECT supported config.
+            if (callback.getCurrentSoftApCapability()
+                    .areFeaturesSupported(
+                    SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) {
+                softApConfigBuilder.setMaxNumberOfClients(10);
+                softApConfigBuilder.setClientControlByUserEnabled(true);
+                softApConfigBuilder.setBlockedClientList(new ArrayList<>());
+                softApConfigBuilder.setAllowedClientList(new ArrayList<>());
+                verifySetGetSoftApConfig(softApConfigBuilder.build());
+            }
+
+            // Test SAE config
+            if (callback.getCurrentSoftApCapability()
+                    .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) {
+                softApConfigBuilder
+                        .setPassphrase(TEST_PASSPHRASE,
+                          SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+                verifySetGetSoftApConfig(softApConfigBuilder.build());
+                softApConfigBuilder
+                        .setPassphrase(TEST_PASSPHRASE,
+                        SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+                verifySetGetSoftApConfig(softApConfigBuilder.build());
+            }
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Verify that startTetheredHotspot with specific channel config.
+     * @throws Exception
+     */
+    public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback()
+            throws Exception {
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+            turnOffWifiAndTetheredHotspotIfEnabled();
+            TestExecutor executor = new TestExecutor();
+            TestSoftApCallback callback = new TestSoftApCallback(mLock);
+            verifyRegisterSoftApCallback(executor, callback);
+
+            SoftApConfiguration testSoftApConfig = new SoftApConfiguration.Builder()
+                    .setSsid(TEST_SSID_UNQUOTED)
+                    .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+                    .setChannel(11, SoftApConfiguration.BAND_2GHZ) // Channel 11 = Freq 2462
+                    .build();
+
+            mWifiManager.setSoftApConfiguration(testSoftApConfig);
+
+            // start tethering which used to verify startTetheredHotspot
+            mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
+                new TetheringManager.StartTetheringCallback() {
+                    @Override
+                    public void onTetheringFailed(final int result) {
+                    }
+                });
+
+            // Verify state and info callback value as expected
+            PollingCheck.check(
+                    "SoftAp channel and state mismatch!!!", 5_000,
+                    () -> { executor.runAll();
+                    return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState() &&
+                    2462 == callback.getCurrentSoftApInfo().getFrequency();
+                    });
+
+            // stop tethering which used to verify stopSoftAp
+            mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+
+            // Verify clean up
+            PollingCheck.check(
+                    "Stop Softap failed", 2_000,
+                    () -> { executor.runAll();
+                    return WifiManager.WIFI_AP_STATE_DISABLED == callback.getCurrentState() &&
+                    0 == callback.getCurrentSoftApInfo().getBandwidth() &&
+                    0 == callback.getCurrentSoftApInfo().getFrequency();
+                    });
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
     private static class TestActionListener implements WifiManager.ActionListener {
         private final Object mLock;
         public boolean onSuccessCalled = false;
@@ -1848,4 +2175,177 @@
         }
         mWifiManager.isEnhancedOpenSupported();
     }
+
+    /**
+     * Test that {@link WifiManager#is5GHzBandSupported()} returns successfully in
+     * both WiFi enabled/disabled states.
+     * Note that the response depends on device support and hence both true/false
+     * are valid responses.
+     */
+    public void testIs5GhzBandSupported() throws Exception {
+        if (!WifiFeature.isWifiSupported(getContext())) {
+            // skip the test if WiFi is not supported
+            return;
+        }
+
+        // Check for 5GHz support with wifi enabled
+        setWifiEnabled(true);
+        PollingCheck.check(
+                "Wifi not enabled!",
+                20000,
+                () -> mWifiManager.isWifiEnabled());
+        boolean isSupportedEnabled = mWifiManager.is5GHzBandSupported();
+
+        // Check for 5GHz support with wifi disabled
+        setWifiEnabled(false);
+        PollingCheck.check(
+                "Wifi not disabled!",
+                20000,
+                () -> !mWifiManager.isWifiEnabled());
+        boolean isSupportedDisabled = mWifiManager.is5GHzBandSupported();
+
+        // If Support is true when WiFi is disable, then it has to be true when it is enabled.
+        // Note, the reverse is a valid case.
+        if (isSupportedDisabled) {
+            assertTrue(isSupportedEnabled);
+        }
+    }
+
+    /**
+     * Test that {@link WifiManager#is6GHzBandSupported()} returns successfully in
+     * both Wifi enabled/disabled states.
+     * Note that the response depends on device support and hence both true/false
+     * are valid responses.
+     */
+    public void testIs6GhzBandSupported() throws Exception {
+        if (!WifiFeature.isWifiSupported(getContext())) {
+            // skip the test if WiFi is not supported
+            return;
+        }
+
+        // Check for 6GHz support with wifi enabled
+        setWifiEnabled(true);
+        PollingCheck.check(
+                "Wifi not enabled!",
+                20000,
+                () -> mWifiManager.isWifiEnabled());
+        boolean isSupportedEnabled = mWifiManager.is6GHzBandSupported();
+
+        // Check for 6GHz support with wifi disabled
+        setWifiEnabled(false);
+        PollingCheck.check(
+                "Wifi not disabled!",
+                20000,
+                () -> !mWifiManager.isWifiEnabled());
+        boolean isSupportedDisabled = mWifiManager.is6GHzBandSupported();
+
+        // If Support is true when WiFi is disable, then it has to be true when it is enabled.
+        // Note, the reverse is a valid case.
+        if (isSupportedDisabled) {
+            assertTrue(isSupportedEnabled);
+        }
+    }
+
+    /**
+     * Test that {@link WifiManager#isWifiStandardSupported()} returns successfully in
+     * both Wifi enabled/disabled states. The test is to be performed on
+     * {@link WifiAnnotations}'s {@code WIFI_STANDARD_}
+     * Note that the response depends on device support and hence both true/false
+     * are valid responses.
+     */
+    public void testIsWifiStandardsSupported() throws Exception {
+        if (!WifiFeature.isWifiSupported(getContext())) {
+            // skip the test if WiFi is not supported
+            return;
+        }
+
+        // Check for WiFi standards support with wifi enabled
+        setWifiEnabled(true);
+        PollingCheck.check(
+                "Wifi not enabled!",
+                20000,
+                () -> mWifiManager.isWifiEnabled());
+        boolean isLegacySupportedEnabled =
+                mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY);
+        boolean is11nSupporedEnabled =
+                mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N);
+        boolean is11acSupportedEnabled =
+                mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC);
+        boolean is11axSupportedEnabled =
+                mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX);
+
+        // Check for WiFi standards support with wifi disabled
+        setWifiEnabled(false);
+        PollingCheck.check(
+                "Wifi not disabled!",
+                20000,
+                () -> !mWifiManager.isWifiEnabled());
+
+        boolean isLegacySupportedDisabled =
+                mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY);
+        boolean is11nSupportedDisabled =
+                mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N);
+        boolean is11acSupportedDisabled =
+                mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC);
+        boolean is11axSupportedDisabled =
+                mWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX);
+
+        if (isLegacySupportedDisabled) {
+            assertTrue(isLegacySupportedEnabled);
+        }
+
+        if (is11nSupportedDisabled) {
+            assertTrue(is11nSupporedEnabled);
+        }
+
+        if (is11acSupportedDisabled) {
+            assertTrue(is11acSupportedEnabled);
+        }
+
+        if (is11axSupportedDisabled) {
+            assertTrue(is11axSupportedEnabled);
+        }
+    }
+
+    private static PasspointConfiguration createPasspointConfiguration() {
+        PasspointConfiguration config = new PasspointConfiguration();
+        HomeSp homeSp = new HomeSp();
+        homeSp.setFqdn("test.com");
+        homeSp.setFriendlyName("friendly name");
+        homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66});
+        config.setHomeSp(homeSp);
+        Credential.SimCredential simCred = new Credential.SimCredential();
+        simCred.setImsi("123456*");
+        simCred.setEapType(23 /* EAP_AKA */);
+        Credential cred = new Credential();
+        cred.setRealm("realm");
+        cred.setSimCredential(simCred);
+        config.setCredential(cred);
+
+        return config;
+    }
+
+    /**
+     * Tests {@link WifiManager#addOrUpdatePasspointConfiguration(PasspointConfiguration)}
+     * adds a Passpoint configuration correctly by getting it once it is added, and comparing it
+     * to the local copy of the configuration.
+     */
+    public void testAddOrUpdatePasspointConfiguration() throws Exception {
+        if (!WifiFeature.isWifiSupported(getContext())) {
+            // skip the test if WiFi is not supported
+            return;
+        }
+
+        // Create and install a Passpoint configuration
+        PasspointConfiguration passpointConfiguration = createPasspointConfiguration();
+        mWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration);
+
+        // Compare configurations
+        List<PasspointConfiguration> configurations = mWifiManager.getPasspointConfigurations();
+        assertNotNull(configurations);
+        assertEquals(passpointConfiguration, configurations.get(0));
+
+        // Clean up
+        mWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn());
+    }
 }
diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java
new file mode 100644
index 0000000..d8f5e57
--- /dev/null
+++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/DeviceWiphyCapabilitiesTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 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.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.DeviceWiphyCapabilities;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** CTS tests for {@link DeviceWiphyCapabilities}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceWiphyCapabilitiesTest {
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip tests if Wifi is not supported
+        assumeTrue(WifiFeature.isWifiSupported(context));
+    }
+
+    /**
+     *  Test that a {@link DeviceWiphyCapabilities} object can be serialized and deserialized,
+     *  while keeping its values unchanged.
+     */
+    @Test
+    public void canSerializeAndDeserialize() {
+        DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities();
+
+        capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true);
+        capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true);
+        capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false);
+
+        Parcel parcel = Parcel.obtain();
+        capa.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        DeviceWiphyCapabilities capaDeserialized =
+                DeviceWiphyCapabilities.CREATOR.createFromParcel(parcel);
+
+        assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N)).isTrue();
+        assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC))
+                .isTrue();
+        assertThat(capaDeserialized.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX))
+                .isFalse();
+        assertThat(capaDeserialized).isEqualTo(capa);
+        assertThat(capaDeserialized.hashCode()).isEqualTo(capa.hashCode());
+    }
+
+    /** Test mapping wifi standard support into channel width support */
+    @Test
+    public void testMappingWifiStandardIntoChannelWidthSupport() {
+        DeviceWiphyCapabilities capa = new DeviceWiphyCapabilities();
+
+        capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, false);
+        capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, false);
+        capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AX, false);
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue();
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isFalse();
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isFalse();
+
+        capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11N, true);
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue();
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isTrue();
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isFalse();
+
+        capa.setWifiStandardSupport(ScanResult.WIFI_STANDARD_11AC, true);
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_20MHZ)).isTrue();
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_40MHZ)).isTrue();
+        assertThat(capa.isChannelWidthSupported(ScanResult.CHANNEL_WIDTH_80MHZ)).isTrue();
+    }
+}
diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java
new file mode 100644
index 0000000..3149b54
--- /dev/null
+++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/NativeWifiClientTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 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.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.MacAddress;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.NativeWifiClient;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** CTS tests for {@link NativeWifiClient}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NativeWifiClientTest {
+
+    private static final byte[] TEST_MAC = { 1, 2, 3, 4, 5, 6 };
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip tests if Wifi is not supported
+        assumeTrue(WifiFeature.isWifiSupported(context));
+    }
+
+    @Test
+    public void testGetters() {
+        NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC));
+
+        assertThat(client.getMacAddress().toByteArray()).isEqualTo(TEST_MAC);
+    }
+
+    @Test
+    public void canSerializeAndDeserialize() {
+        NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC));
+
+        Parcel parcel = Parcel.obtain();
+        client.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        NativeWifiClient clientDeserialized = NativeWifiClient.CREATOR.createFromParcel(parcel);
+
+        assertThat(clientDeserialized.getMacAddress().toByteArray()).isEqualTo(TEST_MAC);
+        assertThat(clientDeserialized).isEqualTo(client);
+        assertThat(clientDeserialized.hashCode()).isEqualTo(client.hashCode());
+    }
+
+    @Test
+    public void testEquals() {
+        NativeWifiClient client = new NativeWifiClient(MacAddress.fromBytes(TEST_MAC));
+        NativeWifiClient client2 =
+                new NativeWifiClient(MacAddress.fromBytes(new byte[] { 7, 8, 9, 10, 11, 12 }));
+
+        assertThat(client2).isNotEqualTo(client);
+    }
+}
diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java
new file mode 100644
index 0000000..f3a8f05
--- /dev/null
+++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoNetworkTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.PnoNetwork;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** CTS tests for {@link PnoNetwork}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PnoNetworkTest {
+
+    private static final byte[] TEST_SSID = { 's', 's', 'i', 'd' };
+    private static final int[] TEST_FREQUENCIES = { 2412, 2417, 5035 };
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip tests if Wifi is not supported
+        assumeTrue(WifiFeature.isWifiSupported(context));
+    }
+
+    @Test
+    public void testGetters() {
+        PnoNetwork network = new PnoNetwork();
+        network.setSsid(TEST_SSID);
+        network.setFrequenciesMhz(TEST_FREQUENCIES);
+        network.setHidden(true);
+
+        assertThat(network.getSsid()).isEqualTo(TEST_SSID);
+        assertThat(network.getFrequenciesMhz()).isEqualTo(TEST_FREQUENCIES);
+        assertThat(network.isHidden()).isTrue();
+    }
+
+    @Test
+    public void canSerializeAndDeserialize() {
+        PnoNetwork network = new PnoNetwork();
+        network.setSsid(TEST_SSID);
+        network.setFrequenciesMhz(TEST_FREQUENCIES);
+        network.setHidden(true);
+
+        Parcel parcel = Parcel.obtain();
+        network.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        PnoNetwork networkDeserialized = PnoNetwork.CREATOR.createFromParcel(parcel);
+
+        assertThat(networkDeserialized.getSsid()).isEqualTo(TEST_SSID);
+        assertThat(networkDeserialized.getFrequenciesMhz()).isEqualTo(TEST_FREQUENCIES);
+        assertThat(networkDeserialized.isHidden()).isTrue();
+        assertThat(networkDeserialized).isEqualTo(network);
+        assertThat(networkDeserialized.hashCode()).isEqualTo(network.hashCode());
+    }
+
+    @Test
+    public void testEquals() {
+        PnoNetwork network = new PnoNetwork();
+        network.setSsid(TEST_SSID);
+        network.setFrequenciesMhz(TEST_FREQUENCIES);
+        network.setHidden(true);
+
+        PnoNetwork network2 = new PnoNetwork();
+        network.setSsid(new byte[] { 'a', 's', 'd', 'f'});
+        network.setFrequenciesMhz(new int[] { 1, 2, 3 });
+        network.setHidden(false);
+
+        assertThat(network2).isNotEqualTo(network);
+    }
+}
diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java
new file mode 100644
index 0000000..59f5d99
--- /dev/null
+++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/PnoSettingsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 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.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.PnoNetwork;
+import android.net.wifi.nl80211.PnoSettings;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+/** CTS tests for {@link PnoSettings}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PnoSettingsTest {
+
+    private static List<PnoNetwork> createTestNetworks() {
+        PnoNetwork network1 = new PnoNetwork();
+        network1.setSsid(new byte[] { 's', 's', 'i', 'd' });
+        network1.setFrequenciesMhz(new int[] { 2412, 2417, 5035 });
+        network1.setHidden(true);
+
+        PnoNetwork network2 = new PnoNetwork();
+        network2.setSsid(new byte[] { 'a', 's', 'd', 'f' });
+        network2.setFrequenciesMhz(new int[] { 2422, 2427, 5040 });
+        network2.setHidden(false);
+
+        return Arrays.asList(network1, network2);
+    }
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip tests if Wifi is not supported
+        assumeTrue(WifiFeature.isWifiSupported(context));
+    }
+
+    @Test
+    public void testGetters() {
+        PnoSettings settings = new PnoSettings();
+        settings.setIntervalMillis(1000);
+        settings.setMin2gRssiDbm(-70);
+        settings.setMin5gRssiDbm(-60);
+        settings.setMin6gRssiDbm(-50);
+        settings.setPnoNetworks(createTestNetworks());
+
+        assertThat(settings.getIntervalMillis()).isEqualTo(1000);
+        assertThat(settings.getMin2gRssiDbm()).isEqualTo(-70);
+        assertThat(settings.getMin5gRssiDbm()).isEqualTo(-60);
+        assertThat(settings.getMin6gRssiDbm()).isEqualTo(-50);
+        assertThat(settings.getPnoNetworks()).isEqualTo(createTestNetworks());
+    }
+
+    @Test
+    public void canSerializeAndDeserialize() {
+        PnoSettings settings = new PnoSettings();
+        settings.setIntervalMillis(1000);
+        settings.setMin2gRssiDbm(-70);
+        settings.setMin5gRssiDbm(-60);
+        settings.setMin6gRssiDbm(-50);
+        settings.setPnoNetworks(createTestNetworks());
+
+        Parcel parcel = Parcel.obtain();
+        settings.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        PnoSettings settingsDeserialized = PnoSettings.CREATOR.createFromParcel(parcel);
+
+        assertThat(settingsDeserialized.getIntervalMillis()).isEqualTo(1000);
+        assertThat(settingsDeserialized.getMin2gRssiDbm()).isEqualTo(-70);
+        assertThat(settingsDeserialized.getMin5gRssiDbm()).isEqualTo(-60);
+        assertThat(settingsDeserialized.getMin6gRssiDbm()).isEqualTo(-50);
+        assertThat(settingsDeserialized.getPnoNetworks()).isEqualTo(createTestNetworks());
+        assertThat(settingsDeserialized).isEqualTo(settings);
+        assertThat(settingsDeserialized.hashCode()).isEqualTo(settings.hashCode());
+    }
+
+    @Test
+    public void testEquals() {
+        PnoSettings settings = new PnoSettings();
+        settings.setIntervalMillis(1000);
+        settings.setMin2gRssiDbm(-70);
+        settings.setMin5gRssiDbm(-60);
+        settings.setMin6gRssiDbm(-50);
+        settings.setPnoNetworks(createTestNetworks());
+
+        PnoSettings settings2 = new PnoSettings();
+        settings.setIntervalMillis(2000);
+        settings.setMin2gRssiDbm(-70);
+        settings.setMin5gRssiDbm(-60);
+        settings.setMin6gRssiDbm(-50);
+        settings.setPnoNetworks(createTestNetworks());
+
+        assertThat(settings2).isNotEqualTo(settings);
+    }
+}
diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java
new file mode 100644
index 0000000..0a76bdb
--- /dev/null
+++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/RadioChainInfoTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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.nl80211.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.RadioChainInfo;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** CTS tests for {@link RadioChainInfo}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RadioChainInfoTest {
+
+    private static final int TEST_CHAIN_ID = 1;
+    private static final int TEST_CHAIN_ID2 = 2;
+    private static final int TEST_LEVEL_DBM = -50;
+    private static final int TEST_LEVEL_DBM2 = -80;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip tests if Wifi is not supported
+        assumeTrue(WifiFeature.isWifiSupported(context));
+    }
+
+    @Test
+    public void testGetters() {
+        RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM);
+        assertThat(info.getChainId()).isEqualTo(TEST_CHAIN_ID);
+        assertThat(info.getLevelDbm()).isEqualTo(TEST_LEVEL_DBM);
+    }
+
+    @Test
+    public void canSerializeAndDeserialize() {
+        RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM);
+
+        Parcel parcel = Parcel.obtain();
+        info.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        RadioChainInfo infoDeserialized = RadioChainInfo.CREATOR.createFromParcel(parcel);
+
+        assertThat(infoDeserialized.getChainId()).isEqualTo(TEST_CHAIN_ID);
+        assertThat(infoDeserialized.getLevelDbm()).isEqualTo(TEST_LEVEL_DBM);
+        assertThat(infoDeserialized).isEqualTo(info);
+        assertThat(infoDeserialized.hashCode()).isEqualTo(info.hashCode());
+    }
+
+    @Test
+    public void testEquals() {
+        RadioChainInfo info = new RadioChainInfo(TEST_CHAIN_ID, TEST_LEVEL_DBM);
+        RadioChainInfo info2 = new RadioChainInfo(TEST_CHAIN_ID2, TEST_LEVEL_DBM2);
+
+        assertThat(info2).isNotEqualTo(info);
+    }
+}
diff --git a/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java b/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java
new file mode 100644
index 0000000..fa8447d
--- /dev/null
+++ b/tests/cts/net/src/android/net/wifi/nl80211/cts/WifiNl80211ManagerTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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.nl80211.cts;
+
+import static android.net.wifi.nl80211.WifiNl80211Manager.OemSecurityType;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.net.wifi.cts.WifiFeature;
+import android.net.wifi.nl80211.WifiNl80211Manager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/** CTS tests for {@link WifiNl80211Manager}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WifiNl80211ManagerTest {
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip tests if Wifi is not supported
+        assumeTrue(WifiFeature.isWifiSupported(context));
+    }
+
+    @Test
+    public void testOemSecurityTypeConstructor() {
+        OemSecurityType securityType = new OemSecurityType(
+                ScanResult.PROTOCOL_WPA,
+                Arrays.asList(ScanResult.KEY_MGMT_PSK, ScanResult.KEY_MGMT_SAE),
+                Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP),
+                ScanResult.CIPHER_CCMP);
+
+        assertThat(securityType.protocol).isEqualTo(ScanResult.PROTOCOL_WPA);
+        assertThat(securityType.keyManagement)
+                .isEqualTo(Arrays.asList(ScanResult.KEY_MGMT_PSK, ScanResult.KEY_MGMT_SAE));
+        assertThat(securityType.pairwiseCipher)
+                .isEqualTo(Arrays.asList(ScanResult.CIPHER_NONE, ScanResult.CIPHER_TKIP));
+        assertThat(securityType.groupCipher).isEqualTo(ScanResult.CIPHER_CCMP);
+    }
+}