Merge "Add visibility rule for migration." am: 447d6af218 am: 72fd984a43 am: 900a7ffa73

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1535542

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ifbe6c9432ff239e50b11add743b05768b576cd86
diff --git a/OsuLogin/AndroidManifest.xml b/OsuLogin/AndroidManifest.xml
index a428cb3..730cd87 100644
--- a/OsuLogin/AndroidManifest.xml
+++ b/OsuLogin/AndroidManifest.xml
@@ -31,7 +31,8 @@
         <activity android:name="com.android.hotspot2.osulogin.OsuLoginActivity"
                   android:label="@string/action_bar_label"
                   android:theme="@style/AppTheme"
-                  android:configChanges="keyboardHidden|orientation|screenSize">
+                  android:configChanges="keyboardHidden|orientation|screenSize"
+                  android:exported="true">
             <intent-filter>
                 <action android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW"/>
                 <category android:name="android.intent.category.DEFAULT"/>
diff --git a/OsuLogin/res/values-af/strings.xml b/OsuLogin/res/values-af/strings.xml
new file mode 100644
index 0000000..bfeee10
--- /dev/null
+++ b/OsuLogin/res/values-af/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Sluit aanlyn aan"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Kon nie aanmeld nie"</string>
+</resources>
diff --git a/OsuLogin/res/values-am/strings.xml b/OsuLogin/res/values-am/strings.xml
new file mode 100644
index 0000000..e27c578
--- /dev/null
+++ b/OsuLogin/res/values-am/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"የመስመር ላይ ምዝገባ"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ምዝገባ አልተሳካም"</string>
+</resources>
diff --git a/OsuLogin/res/values-ar/strings.xml b/OsuLogin/res/values-ar/strings.xml
new file mode 100644
index 0000000..b72d7c1
--- /dev/null
+++ b/OsuLogin/res/values-ar/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"الاشتراك على الإنترنت"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"تعذّر الاشتراك."</string>
+</resources>
diff --git a/OsuLogin/res/values-as/strings.xml b/OsuLogin/res/values-as/strings.xml
new file mode 100644
index 0000000..422de32
--- /dev/null
+++ b/OsuLogin/res/values-as/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"অনলাইনত ছাই আপ কৰক"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ছাইন আপ কৰিব পৰা নগ’ল"</string>
+</resources>
diff --git a/OsuLogin/res/values-az/strings.xml b/OsuLogin/res/values-az/strings.xml
new file mode 100644
index 0000000..977f939
--- /dev/null
+++ b/OsuLogin/res/values-az/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Onlayn Qeydiyyat"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Qeydiyyat alınmadı"</string>
+</resources>
diff --git a/OsuLogin/res/values-b+sr+Latn/strings.xml b/OsuLogin/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..6eb2cc1
--- /dev/null
+++ b/OsuLogin/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Onlajn registracija"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registracija nije uspela"</string>
+</resources>
diff --git a/OsuLogin/res/values-be/strings.xml b/OsuLogin/res/values-be/strings.xml
new file mode 100644
index 0000000..158c3f2
--- /dev/null
+++ b/OsuLogin/res/values-be/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Зарэгістравацца ў інтэрнэце"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Не ўдалося зарэгістравацца"</string>
+</resources>
diff --git a/OsuLogin/res/values-bg/strings.xml b/OsuLogin/res/values-bg/strings.xml
new file mode 100644
index 0000000..ea3145d
--- /dev/null
+++ b/OsuLogin/res/values-bg/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Онлайн регистрация"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Регистрацията не бе успешна"</string>
+</resources>
diff --git a/OsuLogin/res/values-bn/strings.xml b/OsuLogin/res/values-bn/strings.xml
new file mode 100644
index 0000000..c9f615e
--- /dev/null
+++ b/OsuLogin/res/values-bn/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"অনলাইনে সাইন-আপ করুন"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"সাইন-আপ করা যায়নি"</string>
+</resources>
diff --git a/OsuLogin/res/values-bs/strings.xml b/OsuLogin/res/values-bs/strings.xml
new file mode 100644
index 0000000..e9b9751
--- /dev/null
+++ b/OsuLogin/res/values-bs/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online registracija"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registracija nije uspjela"</string>
+</resources>
diff --git a/OsuLogin/res/values-ca/strings.xml b/OsuLogin/res/values-ca/strings.xml
new file mode 100644
index 0000000..7d93096
--- /dev/null
+++ b/OsuLogin/res/values-ca/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Registre en línia"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Ha fallat el registre"</string>
+</resources>
diff --git a/OsuLogin/res/values-cs/strings.xml b/OsuLogin/res/values-cs/strings.xml
new file mode 100644
index 0000000..b9cb794
--- /dev/null
+++ b/OsuLogin/res/values-cs/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online registrace"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registrace selhala"</string>
+</resources>
diff --git a/OsuLogin/res/values-da/strings.xml b/OsuLogin/res/values-da/strings.xml
new file mode 100644
index 0000000..68c93b7
--- /dev/null
+++ b/OsuLogin/res/values-da/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online registrering"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registrering mislykkedes"</string>
+</resources>
diff --git a/OsuLogin/res/values-de/strings.xml b/OsuLogin/res/values-de/strings.xml
new file mode 100644
index 0000000..7e5a310
--- /dev/null
+++ b/OsuLogin/res/values-de/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online-Registrierung"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registrierung fehlgeschlagen"</string>
+</resources>
diff --git a/OsuLogin/res/values-el/strings.xml b/OsuLogin/res/values-el/strings.xml
new file mode 100644
index 0000000..a58e481
--- /dev/null
+++ b/OsuLogin/res/values-el/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Εγγραφή στο διαδίκτυο"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Αποτυχία εγγραφής"</string>
+</resources>
diff --git a/OsuLogin/res/values-en-rAU/strings.xml b/OsuLogin/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..fbbcab1
--- /dev/null
+++ b/OsuLogin/res/values-en-rAU/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online sign-up"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Sign-up failed"</string>
+</resources>
diff --git a/OsuLogin/res/values-en-rCA/strings.xml b/OsuLogin/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..fbbcab1
--- /dev/null
+++ b/OsuLogin/res/values-en-rCA/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online sign-up"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Sign-up failed"</string>
+</resources>
diff --git a/OsuLogin/res/values-en-rGB/strings.xml b/OsuLogin/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..fbbcab1
--- /dev/null
+++ b/OsuLogin/res/values-en-rGB/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online sign-up"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Sign-up failed"</string>
+</resources>
diff --git a/OsuLogin/res/values-en-rIN/strings.xml b/OsuLogin/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..fbbcab1
--- /dev/null
+++ b/OsuLogin/res/values-en-rIN/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online sign-up"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Sign-up failed"</string>
+</resources>
diff --git a/OsuLogin/res/values-en-rXC/strings.xml b/OsuLogin/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..af7ff67
--- /dev/null
+++ b/OsuLogin/res/values-en-rXC/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎OsuLogin‎‏‎‎‏‎"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‏‎‏‎Online Sign Up‎‏‎‎‏‎"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎Sign-up failed‎‏‎‎‏‎"</string>
+</resources>
diff --git a/OsuLogin/res/values-es-rUS/strings.xml b/OsuLogin/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..144804c
--- /dev/null
+++ b/OsuLogin/res/values-es-rUS/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Registrarse en línea"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Se produjo un error de registro"</string>
+</resources>
diff --git a/OsuLogin/res/values-es/strings.xml b/OsuLogin/res/values-es/strings.xml
new file mode 100644
index 0000000..3ad95cd8
--- /dev/null
+++ b/OsuLogin/res/values-es/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Registro online"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Error al completar el registro"</string>
+</resources>
diff --git a/OsuLogin/res/values-et/strings.xml b/OsuLogin/res/values-et/strings.xml
new file mode 100644
index 0000000..94c5cea
--- /dev/null
+++ b/OsuLogin/res/values-et/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Veebis registreerimine"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registreerimine ebaõnnestus"</string>
+</resources>
diff --git a/OsuLogin/res/values-eu/strings.xml b/OsuLogin/res/values-eu/strings.xml
new file mode 100644
index 0000000..30caa87
--- /dev/null
+++ b/OsuLogin/res/values-eu/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Sarean izen-ematea"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Ezin izan da eman izena"</string>
+</resources>
diff --git a/OsuLogin/res/values-fa/strings.xml b/OsuLogin/res/values-fa/strings.xml
new file mode 100644
index 0000000..3005203
--- /dev/null
+++ b/OsuLogin/res/values-fa/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ثبت‌نام آنلاین"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ثبت‌نام انجام نشد"</string>
+</resources>
diff --git a/OsuLogin/res/values-fi/strings.xml b/OsuLogin/res/values-fi/strings.xml
new file mode 100644
index 0000000..24eac8a
--- /dev/null
+++ b/OsuLogin/res/values-fi/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Rekisteröidy verkossa"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Rekisteröityminen ei onnistunut"</string>
+</resources>
diff --git a/OsuLogin/res/values-fr-rCA/strings.xml b/OsuLogin/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..bcaa662
--- /dev/null
+++ b/OsuLogin/res/values-fr-rCA/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Inscription en ligne"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Échec de l\'inscription"</string>
+</resources>
diff --git a/OsuLogin/res/values-fr/strings.xml b/OsuLogin/res/values-fr/strings.xml
new file mode 100644
index 0000000..bcaa662
--- /dev/null
+++ b/OsuLogin/res/values-fr/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Inscription en ligne"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Échec de l\'inscription"</string>
+</resources>
diff --git a/OsuLogin/res/values-gl/strings.xml b/OsuLogin/res/values-gl/strings.xml
new file mode 100644
index 0000000..5fc4444
--- /dev/null
+++ b/OsuLogin/res/values-gl/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Rexistro en liña"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Produciuse un erro co rexistro"</string>
+</resources>
diff --git a/OsuLogin/res/values-gu/strings.xml b/OsuLogin/res/values-gu/strings.xml
new file mode 100644
index 0000000..8449963
--- /dev/null
+++ b/OsuLogin/res/values-gu/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ઑનલાઇન સાઇન અપ કરો"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"સાઇન અપ નિષ્ફળ"</string>
+</resources>
diff --git a/OsuLogin/res/values-hi/strings.xml b/OsuLogin/res/values-hi/strings.xml
new file mode 100644
index 0000000..9e07438
--- /dev/null
+++ b/OsuLogin/res/values-hi/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ऑनलाइन साइन अप करें"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"साइन अप नहीं किया जा सका"</string>
+</resources>
diff --git a/OsuLogin/res/values-hr/strings.xml b/OsuLogin/res/values-hr/strings.xml
new file mode 100644
index 0000000..e9b9751
--- /dev/null
+++ b/OsuLogin/res/values-hr/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online registracija"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registracija nije uspjela"</string>
+</resources>
diff --git a/OsuLogin/res/values-hu/strings.xml b/OsuLogin/res/values-hu/strings.xml
new file mode 100644
index 0000000..cb0e036
--- /dev/null
+++ b/OsuLogin/res/values-hu/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online regisztráció"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"A regisztráció nem sikerült"</string>
+</resources>
diff --git a/OsuLogin/res/values-hy/strings.xml b/OsuLogin/res/values-hy/strings.xml
new file mode 100644
index 0000000..ae1c36a
--- /dev/null
+++ b/OsuLogin/res/values-hy/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Առցանց գրանցում"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Չհաջողվեց գրանցվել"</string>
+</resources>
diff --git a/OsuLogin/res/values-in/strings.xml b/OsuLogin/res/values-in/strings.xml
new file mode 100644
index 0000000..6aaf694
--- /dev/null
+++ b/OsuLogin/res/values-in/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Pendaftaran Online"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Pendaftaran gagal"</string>
+</resources>
diff --git a/OsuLogin/res/values-is/strings.xml b/OsuLogin/res/values-is/strings.xml
new file mode 100644
index 0000000..f1ae520
--- /dev/null
+++ b/OsuLogin/res/values-is/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Skráning á netinu"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Skráning mistókst"</string>
+</resources>
diff --git a/OsuLogin/res/values-it/strings.xml b/OsuLogin/res/values-it/strings.xml
new file mode 100644
index 0000000..fbff7b0
--- /dev/null
+++ b/OsuLogin/res/values-it/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Registrazione online"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registrazione non riuscita"</string>
+</resources>
diff --git a/OsuLogin/res/values-iw/strings.xml b/OsuLogin/res/values-iw/strings.xml
new file mode 100644
index 0000000..866ef88
--- /dev/null
+++ b/OsuLogin/res/values-iw/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"הרשמה אונליין"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ההרשמה נכשלה"</string>
+</resources>
diff --git a/OsuLogin/res/values-ja/strings.xml b/OsuLogin/res/values-ja/strings.xml
new file mode 100644
index 0000000..8a220d6
--- /dev/null
+++ b/OsuLogin/res/values-ja/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"オンライン登録"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"登録できませんでした"</string>
+</resources>
diff --git a/OsuLogin/res/values-ka/strings.xml b/OsuLogin/res/values-ka/strings.xml
new file mode 100644
index 0000000..bf08006
--- /dev/null
+++ b/OsuLogin/res/values-ka/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ონლაინ რეგისტრაცია"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"რეგისტრაცია ვერ მოხერხდა"</string>
+</resources>
diff --git a/OsuLogin/res/values-kk/strings.xml b/OsuLogin/res/values-kk/strings.xml
new file mode 100644
index 0000000..8b87356
--- /dev/null
+++ b/OsuLogin/res/values-kk/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Онлайн тіркелу"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Тіркелмеді."</string>
+</resources>
diff --git a/OsuLogin/res/values-km/strings.xml b/OsuLogin/res/values-km/strings.xml
new file mode 100644
index 0000000..f58ccc3
--- /dev/null
+++ b/OsuLogin/res/values-km/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ការចុះឈ្មោះ​លើអ៊ីនធឺណិត"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ការចុះឈ្មោះ​មិនបានសម្រេច"</string>
+</resources>
diff --git a/OsuLogin/res/values-kn/strings.xml b/OsuLogin/res/values-kn/strings.xml
new file mode 100644
index 0000000..49a6562
--- /dev/null
+++ b/OsuLogin/res/values-kn/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ಆನ್‌ಲೈನ್ ಸೈನ್ ಅಪ್"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ಸೈನ್ ಅಪ್ ವಿಫಲವಾಗಿದೆ"</string>
+</resources>
diff --git a/OsuLogin/res/values-ko/strings.xml b/OsuLogin/res/values-ko/strings.xml
new file mode 100644
index 0000000..e647ca0
--- /dev/null
+++ b/OsuLogin/res/values-ko/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"온라인 가입"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"가입에 실패했습니다."</string>
+</resources>
diff --git a/OsuLogin/res/values-ky/strings.xml b/OsuLogin/res/values-ky/strings.xml
new file mode 100644
index 0000000..42da248
--- /dev/null
+++ b/OsuLogin/res/values-ky/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Интернет аркылуу катталуу"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Катталган жоксуз"</string>
+</resources>
diff --git a/OsuLogin/res/values-lo/strings.xml b/OsuLogin/res/values-lo/strings.xml
new file mode 100644
index 0000000..9ff2241
--- /dev/null
+++ b/OsuLogin/res/values-lo/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ສະໝັກອອນລາຍ"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ສະໝັກບໍ່ສຳເລັດ"</string>
+</resources>
diff --git a/OsuLogin/res/values-lt/strings.xml b/OsuLogin/res/values-lt/strings.xml
new file mode 100644
index 0000000..1a4c06e
--- /dev/null
+++ b/OsuLogin/res/values-lt/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Internetinis prisiregistravimas"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Nepavyko prisiregistruoti"</string>
+</resources>
diff --git a/OsuLogin/res/values-lv/strings.xml b/OsuLogin/res/values-lv/strings.xml
new file mode 100644
index 0000000..11cdb97
--- /dev/null
+++ b/OsuLogin/res/values-lv/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Reģistrācija tiešsaistē"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Reģistrācija neizdevās."</string>
+</resources>
diff --git a/OsuLogin/res/values-mk/strings.xml b/OsuLogin/res/values-mk/strings.xml
new file mode 100644
index 0000000..de608e1
--- /dev/null
+++ b/OsuLogin/res/values-mk/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Онлајн регистрација"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Регистрацијата не успеа"</string>
+</resources>
diff --git a/OsuLogin/res/values-ml/strings.xml b/OsuLogin/res/values-ml/strings.xml
new file mode 100644
index 0000000..8e797c8
--- /dev/null
+++ b/OsuLogin/res/values-ml/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ഓൺലെെൻ സെെൻ അപ്പ്"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"സൈൻ അപ്പ് ചെയ്യാനായില്ല"</string>
+</resources>
diff --git a/OsuLogin/res/values-mn/strings.xml b/OsuLogin/res/values-mn/strings.xml
new file mode 100644
index 0000000..59d79d0
--- /dev/null
+++ b/OsuLogin/res/values-mn/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Онлайнаар бүртгүүлэх"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Бүртгүүлж чадсангүй"</string>
+</resources>
diff --git a/OsuLogin/res/values-mr/strings.xml b/OsuLogin/res/values-mr/strings.xml
new file mode 100644
index 0000000..15479a6
--- /dev/null
+++ b/OsuLogin/res/values-mr/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ऑनलाइन साइन अप करा"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"साइन-अप करता आले नाही"</string>
+</resources>
diff --git a/OsuLogin/res/values-ms/strings.xml b/OsuLogin/res/values-ms/strings.xml
new file mode 100644
index 0000000..7e1cf95
--- /dev/null
+++ b/OsuLogin/res/values-ms/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Pendaftaran Dalam Talian"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Pendaftaran gagal"</string>
+</resources>
diff --git a/OsuLogin/res/values-my/strings.xml b/OsuLogin/res/values-my/strings.xml
new file mode 100644
index 0000000..1bd992e
--- /dev/null
+++ b/OsuLogin/res/values-my/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"အွန်လိုင်း အကောင့်ဖွင့်ရန်"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"အကောင့်ဖွင့်၍ မရပါ"</string>
+</resources>
diff --git a/OsuLogin/res/values-nb/strings.xml b/OsuLogin/res/values-nb/strings.xml
new file mode 100644
index 0000000..2e0c47a
--- /dev/null
+++ b/OsuLogin/res/values-nb/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Registrering på nettet"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registreringen mislyktes"</string>
+</resources>
diff --git a/OsuLogin/res/values-ne/strings.xml b/OsuLogin/res/values-ne/strings.xml
new file mode 100644
index 0000000..16bd92f
--- /dev/null
+++ b/OsuLogin/res/values-ne/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"अनलाइन साइन अप"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"साइन अप गर्न सकिएन"</string>
+</resources>
diff --git a/OsuLogin/res/values-nl/strings.xml b/OsuLogin/res/values-nl/strings.xml
new file mode 100644
index 0000000..7cf8bd2
--- /dev/null
+++ b/OsuLogin/res/values-nl/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online aanmelding"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Aanmelding mislukt"</string>
+</resources>
diff --git a/OsuLogin/res/values-or/strings.xml b/OsuLogin/res/values-or/strings.xml
new file mode 100644
index 0000000..e0584d7
--- /dev/null
+++ b/OsuLogin/res/values-or/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ଅନଲାଇନ୍ ସାଇନ୍ ଅପ୍ କରନ୍ତୁ"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ସାଇନ୍ ଅପ୍ ବିଫଳ ହୋଇଛି"</string>
+</resources>
diff --git a/OsuLogin/res/values-pa/strings.xml b/OsuLogin/res/values-pa/strings.xml
new file mode 100644
index 0000000..7e47d0e
--- /dev/null
+++ b/OsuLogin/res/values-pa/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ਆਨਲਾਈਨ ਸਾਈਨ-ਅੱਪ ਕਰੋ"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ਸਾਈਨ-ਅੱਪ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
+</resources>
diff --git a/OsuLogin/res/values-pl/strings.xml b/OsuLogin/res/values-pl/strings.xml
new file mode 100644
index 0000000..c0722ab
--- /dev/null
+++ b/OsuLogin/res/values-pl/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Rejestracja online"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Nie udało się zarejestrować"</string>
+</resources>
diff --git a/OsuLogin/res/values-pt-rBR/strings.xml b/OsuLogin/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..c9fe377
--- /dev/null
+++ b/OsuLogin/res/values-pt-rBR/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Inscrição on-line"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Falha na inscrição"</string>
+</resources>
diff --git a/OsuLogin/res/values-pt-rPT/strings.xml b/OsuLogin/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..0059281
--- /dev/null
+++ b/OsuLogin/res/values-pt-rPT/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Inscrição online"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Falha na inscrição."</string>
+</resources>
diff --git a/OsuLogin/res/values-pt/strings.xml b/OsuLogin/res/values-pt/strings.xml
new file mode 100644
index 0000000..c9fe377
--- /dev/null
+++ b/OsuLogin/res/values-pt/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Inscrição on-line"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Falha na inscrição"</string>
+</resources>
diff --git a/OsuLogin/res/values-ro/strings.xml b/OsuLogin/res/values-ro/strings.xml
new file mode 100644
index 0000000..eead127
--- /dev/null
+++ b/OsuLogin/res/values-ro/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Înscriere online"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Nu s-a înscris"</string>
+</resources>
diff --git a/OsuLogin/res/values-ru/strings.xml b/OsuLogin/res/values-ru/strings.xml
new file mode 100644
index 0000000..a271ef7
--- /dev/null
+++ b/OsuLogin/res/values-ru/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Регистрация в Интернете"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Не удалось зарегистрироваться."</string>
+</resources>
diff --git a/OsuLogin/res/values-si/strings.xml b/OsuLogin/res/values-si/strings.xml
new file mode 100644
index 0000000..52e5979
--- /dev/null
+++ b/OsuLogin/res/values-si/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"සබැඳි ලියාපදිංචිය"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ලියාපදිංචිය අසාර්ථක විය"</string>
+</resources>
diff --git a/OsuLogin/res/values-sk/strings.xml b/OsuLogin/res/values-sk/strings.xml
new file mode 100644
index 0000000..f6b9f70
--- /dev/null
+++ b/OsuLogin/res/values-sk/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online registrácia"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registrácia zlyhala"</string>
+</resources>
diff --git a/OsuLogin/res/values-sl/strings.xml b/OsuLogin/res/values-sl/strings.xml
new file mode 100644
index 0000000..6e6b95c
--- /dev/null
+++ b/OsuLogin/res/values-sl/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Spletna registracija"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registracija ni uspela"</string>
+</resources>
diff --git a/OsuLogin/res/values-sq/strings.xml b/OsuLogin/res/values-sq/strings.xml
new file mode 100644
index 0000000..f67a238
--- /dev/null
+++ b/OsuLogin/res/values-sq/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Regjistrimi në linjë"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Regjistrimi dështoi"</string>
+</resources>
diff --git a/OsuLogin/res/values-sr/strings.xml b/OsuLogin/res/values-sr/strings.xml
new file mode 100644
index 0000000..14e0828
--- /dev/null
+++ b/OsuLogin/res/values-sr/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Онлајн регистрација"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Регистрација није успела"</string>
+</resources>
diff --git a/OsuLogin/res/values-sv/strings.xml b/OsuLogin/res/values-sv/strings.xml
new file mode 100644
index 0000000..ea5fdfd
--- /dev/null
+++ b/OsuLogin/res/values-sv/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Registrering online"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registreringen misslyckades"</string>
+</resources>
diff --git a/OsuLogin/res/values-sw/strings.xml b/OsuLogin/res/values-sw/strings.xml
new file mode 100644
index 0000000..c20a402
--- /dev/null
+++ b/OsuLogin/res/values-sw/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Kujisajili Mtandaoni"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Imeshindwa kukusajili"</string>
+</resources>
diff --git a/OsuLogin/res/values-ta/strings.xml b/OsuLogin/res/values-ta/strings.xml
new file mode 100644
index 0000000..e2eb567
--- /dev/null
+++ b/OsuLogin/res/values-ta/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ஆன்லைனில் பதிவு செய்"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"பதிவு செய்ய முடியவில்லை"</string>
+</resources>
diff --git a/OsuLogin/res/values-te/strings.xml b/OsuLogin/res/values-te/strings.xml
new file mode 100644
index 0000000..56b0b44
--- /dev/null
+++ b/OsuLogin/res/values-te/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"ఆన్‌లైన్ సైన్ అప్"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"సైన్-అప్ విఫలమయ్యింది"</string>
+</resources>
diff --git a/OsuLogin/res/values-th/strings.xml b/OsuLogin/res/values-th/strings.xml
new file mode 100644
index 0000000..552dca2
--- /dev/null
+++ b/OsuLogin/res/values-th/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"การลงชื่อสมัครใช้ออนไลน์"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"ลงชื่อสมัครใช้ไม่สำเร็จ"</string>
+</resources>
diff --git a/OsuLogin/res/values-tl/strings.xml b/OsuLogin/res/values-tl/strings.xml
new file mode 100644
index 0000000..ba89e96
--- /dev/null
+++ b/OsuLogin/res/values-tl/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Pag-sign Up Online"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Hindi nakapag-sign up"</string>
+</resources>
diff --git a/OsuLogin/res/values-tr/strings.xml b/OsuLogin/res/values-tr/strings.xml
new file mode 100644
index 0000000..1d927fe
--- /dev/null
+++ b/OsuLogin/res/values-tr/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Online Kaydolma"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Kaydolma işlemi başarısız oldu"</string>
+</resources>
diff --git a/OsuLogin/res/values-uk/strings.xml b/OsuLogin/res/values-uk/strings.xml
new file mode 100644
index 0000000..6e60ff0
--- /dev/null
+++ b/OsuLogin/res/values-uk/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Онлайн-реєстрація"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Не вдалося зареєструватись"</string>
+</resources>
diff --git a/OsuLogin/res/values-ur/strings.xml b/OsuLogin/res/values-ur/strings.xml
new file mode 100644
index 0000000..eed7686
--- /dev/null
+++ b/OsuLogin/res/values-ur/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"آن لائن سائن اپ کریں"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"سائن اپ ناکام ہو گیا"</string>
+</resources>
diff --git a/OsuLogin/res/values-uz/strings.xml b/OsuLogin/res/values-uz/strings.xml
new file mode 100644
index 0000000..152d129
--- /dev/null
+++ b/OsuLogin/res/values-uz/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Onlayn registratsiya"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Registratsiya qilinmadi"</string>
+</resources>
diff --git a/OsuLogin/res/values-vi/strings.xml b/OsuLogin/res/values-vi/strings.xml
new file mode 100644
index 0000000..8455807
--- /dev/null
+++ b/OsuLogin/res/values-vi/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Đăng ký trực tuyến"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Không đăng ký được"</string>
+</resources>
diff --git a/OsuLogin/res/values-zh-rCN/strings.xml b/OsuLogin/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..7f13647
--- /dev/null
+++ b/OsuLogin/res/values-zh-rCN/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"在线注册"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"注册失败"</string>
+</resources>
diff --git a/OsuLogin/res/values-zh-rHK/strings.xml b/OsuLogin/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..8731791
--- /dev/null
+++ b/OsuLogin/res/values-zh-rHK/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"網上申請"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"無法申請"</string>
+</resources>
diff --git a/OsuLogin/res/values-zh-rTW/strings.xml b/OsuLogin/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..79208c8
--- /dev/null
+++ b/OsuLogin/res/values-zh-rTW/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"線上註冊"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"註冊失敗"</string>
+</resources>
diff --git a/OsuLogin/res/values-zu/strings.xml b/OsuLogin/res/values-zu/strings.xml
new file mode 100644
index 0000000..27ac6bb
--- /dev/null
+++ b/OsuLogin/res/values-zu/strings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="8288271429327488421">"I-OsuLogin"</string>
+    <string name="action_bar_label" msgid="550995560341508693">"Ukubhalisa Okuku-inthanethi"</string>
+    <string name="sign_up_failed" msgid="837216244603867568">"Ukubhalisa kuhlulekile"</string>
+</resources>
diff --git a/framework/Android.bp b/framework/Android.bp
index 49138ab..6976c5c 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -40,6 +40,7 @@
     srcs: [
         ":framework-wifi-updatable-java-sources",
         ":framework-wifi-updatable-exported-aidl-sources",
+        ":module-utils-os-aidls",
     ],
 }
 
@@ -60,7 +61,6 @@
     "//external/robolectric-shadows:__subpackages__",
     "//frameworks/base/packages/SettingsLib/tests/integ",
     "//external/sl4a:__subpackages__",
-    "//packages/apps/Settings/tests/robotests", // TODO(b/161767237): remove
 ]
 
 // defaults shared between `framework-wifi` & `framework-wifi-pre-jarjar`
@@ -73,13 +73,14 @@
         "framework-wifi-util-lib",
         "android.hardware.wifi-V1.0-java-constants",
         "modules-utils-build",
+        "modules-utils-os",
     ],
     libs: [
         "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
     ],
     srcs: [
         ":framework-wifi-updatable-sources",
-        ":framework-wifi-util-lib-aidls",
+        ":module-utils-os-aidls",
     ],
 }
 
@@ -135,7 +136,7 @@
 // defaults for tests that need to build against framework-wifi's @hide APIs
 java_defaults {
     name: "framework-wifi-test-defaults",
-    sdk_version: "core_platform", // tests can use @CorePlatformApi's
+    sdk_version: "core_current",
     libs: [
         // order matters: classes in framework-wifi are resolved before framework, meaning
         // @hide APIs in framework-wifi are resolved before @SystemApi stubs in framework
diff --git a/framework/TEST_MAPPING b/framework/TEST_MAPPING
new file mode 100644
index 0000000..7ddc308
--- /dev/null
+++ b/framework/TEST_MAPPING
@@ -0,0 +1,22 @@
+{
+  "presubmit-large": [
+    {
+      "name": "CtsWifiTestCases",
+      "options": [
+        {
+          "exclude-annotation": "android.net.wifi.cts.VirtualDeviceNotSupported"
+        }
+      ]
+    }
+  ],
+  "mainline-presubmit": [
+    {
+      "name": "CtsWifiTestCases[com.google.android.wifi.apex]",
+      "options": [
+        {
+          "exclude-annotation": "android.net.wifi.cts.VirtualDeviceNotSupported"
+        }
+      ]
+    }
+  ]
+}
diff --git a/framework/java/android/net/wifi/ITxPacketCountListener.aidl b/framework/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl
similarity index 60%
copy from framework/java/android/net/wifi/ITxPacketCountListener.aidl
copy to framework/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl
index 9105bd0..cb359e9 100644
--- a/framework/java/android/net/wifi/ITxPacketCountListener.aidl
+++ b/framework/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
+/**
+ * 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
+ *     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,
@@ -16,13 +16,4 @@
 
 package android.net.wifi;
 
-/**
- * Interface for tx packet counter callback.
- * @deprecated no longer used, remove once removed from BaseWifiService
- * @hide
- */
-oneway interface ITxPacketCountListener
-{
-    void onSuccess(int count);
-    void onFailure(int reason);
-}
+parcelable CoexUnsafeChannel;
diff --git a/framework/java/android/net/wifi/ITxPacketCountListener.aidl b/framework/aidl-export/android/net/wifi/aware/AwareResources.aidl
similarity index 63%
copy from framework/java/android/net/wifi/ITxPacketCountListener.aidl
copy to framework/aidl-export/android/net/wifi/aware/AwareResources.aidl
index 9105bd0..d0bd2dd 100644
--- a/framework/java/android/net/wifi/ITxPacketCountListener.aidl
+++ b/framework/aidl-export/android/net/wifi/aware/AwareResources.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi;
+package android.net.wifi.aware;
 
-/**
- * Interface for tx packet counter callback.
- * @deprecated no longer used, remove once removed from BaseWifiService
- * @hide
- */
-oneway interface ITxPacketCountListener
-{
-    void onSuccess(int count);
-    void onFailure(int reason);
-}
+parcelable AwareResources;
\ No newline at end of file
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 53c3b33..1ece79a 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -14,6 +14,7 @@
     field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
     field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
     field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+    field public static final int EASY_CONNECT_EVENT_FAILURE_URI_GENERATION = -13; // 0xfffffff3
   }
 
   public final class ScanResult implements android.os.Parcelable {
@@ -34,6 +35,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.ScanResult> CREATOR;
     field public String SSID;
     field public static final int WIFI_STANDARD_11AC = 5; // 0x5
+    field public static final int WIFI_STANDARD_11AD = 7; // 0x7
     field public static final int WIFI_STANDARD_11AX = 6; // 0x6
     field public static final int WIFI_STANDARD_11N = 4; // 0x4
     field public static final int WIFI_STANDARD_LEGACY = 1; // 0x1
@@ -105,6 +107,8 @@
     field @Deprecated public String FQDN;
     field @Deprecated public static final int SECURITY_TYPE_EAP = 3; // 0x3
     field @Deprecated public static final int SECURITY_TYPE_EAP_SUITE_B = 5; // 0x5
+    field @Deprecated public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE = 9; // 0x9
+    field @Deprecated public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT = 5; // 0x5
     field @Deprecated public static final int SECURITY_TYPE_OPEN = 0; // 0x0
     field @Deprecated public static final int SECURITY_TYPE_OWE = 6; // 0x6
     field @Deprecated public static final int SECURITY_TYPE_PSK = 2; // 0x2
@@ -144,6 +148,7 @@
 
   @Deprecated public static class WifiConfiguration.GroupCipher {
     field @Deprecated public static final int CCMP = 3; // 0x3
+    field @Deprecated public static final int GCMP_128 = 7; // 0x7
     field @Deprecated public static final int GCMP_256 = 5; // 0x5
     field @Deprecated public static final int SMS4 = 6; // 0x6
     field @Deprecated public static final int TKIP = 2; // 0x2
@@ -173,6 +178,7 @@
 
   @Deprecated public static class WifiConfiguration.PairwiseCipher {
     field @Deprecated public static final int CCMP = 2; // 0x2
+    field @Deprecated public static final int GCMP_128 = 5; // 0x5
     field @Deprecated public static final int GCMP_256 = 3; // 0x3
     field @Deprecated public static final int NONE = 0; // 0x0
     field @Deprecated public static final int SMS4 = 4; // 0x4
@@ -304,6 +310,7 @@
     method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int addNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
     method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public void addSuggestionConnectionStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean addSuggestionUserApprovalStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SuggestionUserApprovalStatusListener);
     method @Deprecated public static int calculateSignalLevel(int, int);
     method @IntRange(from=0) public int calculateSignalLevel(int);
     method @Deprecated public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
@@ -319,6 +326,7 @@
     method public android.net.DhcpInfo getDhcpInfo();
     method public int getMaxNumberOfNetworkSuggestionsPerApp();
     method @IntRange(from=0) public int getMaxSignalLevel();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getNetworkSuggestionUserApprovalStatus();
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
@@ -326,19 +334,23 @@
     method public boolean is5GHzBandSupported();
     method public boolean is6GHzBandSupported();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isAutoWakeupEnabled();
+    method public boolean isBridgedApConcurrencySupported();
     method @Deprecated public boolean isDeviceToApRttSupported();
     method public boolean isEasyConnectSupported();
     method public boolean isEnhancedOpenSupported();
     method public boolean isEnhancedPowerReportingSupported();
+    method public boolean isMultiStaConcurrencySupported();
     method public boolean isP2pSupported();
     method public boolean isPreferredNetworkOffloadSupported();
     method @Deprecated public boolean isScanAlwaysAvailable();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isScanThrottleEnabled();
     method public boolean isStaApConcurrencySupported();
+    method public boolean isStaBridgedApConcurrencySupported();
     method public boolean isTdlsSupported();
     method public boolean isWapiSupported();
     method public boolean isWifiEnabled();
     method public boolean isWifiStandardSupported(int);
+    method public boolean isWpa3ApValidationSupported();
     method public boolean isWpa3SaeSupported();
     method public boolean isWpa3SuiteBSupported();
     method @Deprecated public boolean pingSupplicant();
@@ -349,6 +361,7 @@
     method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int removeNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_CARRIER_PROVISIONING}) public void removePasspointConfiguration(String);
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeSuggestionConnectionStatusListener(@NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeSuggestionUserApprovalStatusListener(@NonNull android.net.wifi.WifiManager.SuggestionUserApprovalStatusListener);
     method @Deprecated public boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(String, boolean);
@@ -387,6 +400,11 @@
     field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1; // 0x1
     field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5; // 0x5
     field public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0; // 0x0
+    field public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE = 4; // 0x4
+    field public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER = 2; // 0x2
+    field public static final int STATUS_SUGGESTION_APPROVAL_PENDING = 1; // 0x1
+    field public static final int STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER = 3; // 0x3
+    field public static final int STATUS_SUGGESTION_APPROVAL_UNKNOWN = 0; // 0x0
     field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1; // 0x1
     field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2; // 0x2
     field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3; // 0x3
@@ -444,6 +462,10 @@
     method public void onConnectionStatus(@NonNull android.net.wifi.WifiNetworkSuggestion, int);
   }
 
+  public static interface WifiManager.SuggestionUserApprovalStatusListener {
+    method public void onUserApprovalStatusChange();
+  }
+
   public class WifiManager.WifiLock {
     method public void acquire();
     method public boolean isHeld();
@@ -476,7 +498,9 @@
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setSsidPattern(@NonNull android.os.PatternMatcher);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa2Passphrase(@NonNull String);
-    method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa3EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa3Enterprise192BitModeConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method @Deprecated @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa3EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa3EnterpriseStandardModeConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa3Passphrase(@NonNull String);
   }
 
@@ -487,8 +511,11 @@
     method @Nullable public String getPassphrase();
     method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig();
     method @IntRange(from=0) public int getPriority();
+    method public int getPriorityGroup();
     method @Nullable public String getSsid();
+    method public int getSubscriptionId();
     method public boolean isAppInteractionRequired();
+    method public boolean isCarrierMerged();
     method public boolean isCredentialSharedWithUser();
     method public boolean isEnhancedOpen();
     method public boolean isHiddenSsid();
@@ -504,8 +531,10 @@
     ctor public WifiNetworkSuggestion.Builder();
     method @NonNull public android.net.wifi.WifiNetworkSuggestion build();
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setBssid(@NonNull android.net.MacAddress);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierMerged(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setCredentialSharedWithUser(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedMacRandomizationEnabled(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsInitialAutojoinEnabled(boolean);
@@ -513,13 +542,17 @@
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSubscriptionId(int);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiPassphrase(@NonNull String);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2Passphrase(@NonNull String);
-    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa3EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa3Enterprise192BitModeConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method @Deprecated @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa3EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa3EnterpriseStandardModeConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa3Passphrase(@NonNull String);
   }
 
@@ -549,12 +582,22 @@
     method public void onAttached(android.net.wifi.aware.WifiAwareSession);
   }
 
+  public final class AwareResources implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getNumOfAvailableDataPaths();
+    method public int getNumOfAvailablePublishSessions();
+    method public int getNumOfAvailableSubscribeSessions();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.AwareResources> CREATOR;
+  }
+
   public final class Characteristics implements android.os.Parcelable {
     method public int describeContents();
     method public int getMaxMatchFilterLength();
     method public int getMaxServiceNameLength();
     method public int getMaxServiceSpecificInfoLength();
     method public int getSupportedCipherSuites();
+    method public boolean isInstantCommunicationModeSupported();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
     field public static final int WIFI_AWARE_CIPHER_SUITE_NCS_SK_128 = 1; // 0x1
@@ -576,6 +619,7 @@
     method public void onPublishStarted(@NonNull android.net.wifi.aware.PublishDiscoverySession);
     method public void onServiceDiscovered(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>);
     method public void onServiceDiscoveredWithinRange(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>, int);
+    method public void onServiceLost(@NonNull android.net.wifi.aware.PeerHandle, int);
     method public void onSessionConfigFailed();
     method public void onSessionConfigUpdated();
     method public void onSessionTerminated();
@@ -649,11 +693,16 @@
   public class WifiAwareManager {
     method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @Nullable android.os.Handler);
     method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @NonNull android.net.wifi.aware.IdentityChangedListener, @Nullable android.os.Handler);
-    method public android.net.wifi.aware.Characteristics getCharacteristics();
+    method @Nullable public android.net.wifi.aware.AwareResources getAvailableAwareResources();
+    method @Nullable public android.net.wifi.aware.Characteristics getCharacteristics();
     method public boolean isAvailable();
+    method public boolean isDeviceAttached();
+    method public boolean isInstantCommunicationModeEnabled();
     field public static final String ACTION_WIFI_AWARE_STATE_CHANGED = "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
     field public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; // 0x0
     field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
+    field public static final int WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE = 1; // 0x1
+    field public static final int WIFI_AWARE_DISCOVERY_LOST_REASON_UNKNOWN = 0; // 0x0
   }
 
   public final class WifiAwareNetworkInfo implements android.os.Parcelable android.net.TransportInfo {
@@ -791,9 +840,15 @@
     method public int describeContents();
     method public String getFqdn();
     method public String getFriendlyName();
+    method @Nullable public long[] getMatchAllOis();
+    method @Nullable public long[] getMatchAnyOis();
+    method @NonNull public java.util.Collection<java.lang.String> getOtherHomePartnersList();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(String);
     method public void setFriendlyName(String);
+    method public void setMatchAllOis(@Nullable long[]);
+    method public void setMatchAnyOis(@Nullable long[]);
+    method public void setOtherHomePartnersList(@NonNull java.util.Collection<java.lang.String>);
     method public void setRoamingConsortiumOis(long[]);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
@@ -1108,7 +1163,11 @@
 
   public final class RangingRequest implements android.os.Parcelable {
     method public int describeContents();
+    method public static int getDefaultRttBurstSize();
     method public static int getMaxPeers();
+    method public static int getMaxRttBurstSize();
+    method public static int getMinRttBurstSize();
+    method public int getRttBurstSize();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingRequest> CREATOR;
   }
@@ -1120,6 +1179,7 @@
     method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(@NonNull android.net.MacAddress);
     method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(@NonNull android.net.wifi.aware.PeerHandle);
     method public android.net.wifi.rtt.RangingRequest build();
+    method @NonNull public android.net.wifi.rtt.RangingRequest.Builder setRttBurstSize(int);
   }
 
   public final class RangingResult implements android.os.Parcelable {
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 07793c1..23e3962 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -1,8 +1,20 @@
 // Signature format: 2.0
 package android.net.wifi {
 
+  public final class CoexUnsafeChannel implements android.os.Parcelable {
+    ctor public CoexUnsafeChannel(int, int);
+    ctor public CoexUnsafeChannel(int, int, int);
+    method public int getBand();
+    method public int getChannel();
+    method public int getPowerCapDbm();
+    method public boolean isPowerCapAvailable();
+    method public void setPowerCapDbm(int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.CoexUnsafeChannel> CREATOR;
+  }
+
   public abstract class EasyConnectStatusCallback {
     ctor public EasyConnectStatusCallback();
+    method public void onBootstrapUriGenerated(@NonNull String);
     method public abstract void onConfiguratorSuccess(int);
     method public abstract void onEnrolleeSuccess(int);
     method public void onFailure(int);
@@ -241,18 +253,23 @@
     method public boolean areFeaturesSupported(long);
     method public int describeContents();
     method public int getMaxSupportedClients();
+    method @NonNull public int[] getSupportedChannelList(int);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApCapability> CREATOR;
     field public static final long SOFTAP_FEATURE_ACS_OFFLOAD = 1L; // 0x1L
     field public static final long SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 2L; // 0x2L
+    field public static final long SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION = 8L; // 0x8L
     field public static final long SOFTAP_FEATURE_WPA3_SAE = 4L; // 0x4L
   }
 
   public final class SoftApConfiguration implements android.os.Parcelable {
     method @NonNull public java.util.List<android.net.MacAddress> getAllowedClientList();
     method public int getBand();
+    method @NonNull public int[] getBands();
     method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList();
     method public int getChannel();
+    method @NonNull public android.util.SparseIntArray getChannels();
+    method public int getMacRandomizationSetting();
     method public int getMaxNumberOfClients();
     method public long getShutdownTimeoutMillis();
     method public boolean isAutoShutdownEnabled();
@@ -260,8 +277,11 @@
     method @Nullable public android.net.wifi.WifiConfiguration toWifiConfiguration();
     field public static final int BAND_2GHZ = 1; // 0x1
     field public static final int BAND_5GHZ = 2; // 0x2
+    field public static final int BAND_60GHZ = 8; // 0x8
     field public static final int BAND_6GHZ = 4; // 0x4
-    field public static final int BAND_ANY = 7; // 0x7
+    field @Deprecated public static final int BAND_ANY = 7; // 0x7
+    field public static final int RANDOMIZATION_NONE = 0; // 0x0
+    field public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
   }
 
   public static final class SoftApConfiguration.Builder {
@@ -271,11 +291,14 @@
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAllowedClientList(@NonNull java.util.List<android.net.MacAddress>);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAutoShutdownEnabled(boolean);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBands(@NonNull int[]);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBlockedClientList(@NonNull java.util.List<android.net.MacAddress>);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannels(@NonNull android.util.SparseIntArray);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientControlByUserEnabled(boolean);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMacRandomizationSetting(int);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(@IntRange(from=0) int);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0) long);
@@ -285,14 +308,20 @@
   public final class SoftApInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getBandwidth();
+    method @Nullable public android.net.MacAddress getBssid();
     method public int getFrequency();
+    method public int getWifiStandard();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int CHANNEL_WIDTH_160MHZ = 6; // 0x6
     field public static final int CHANNEL_WIDTH_20MHZ = 2; // 0x2
     field public static final int CHANNEL_WIDTH_20MHZ_NOHT = 1; // 0x1
+    field public static final int CHANNEL_WIDTH_2160MHZ = 7; // 0x7
     field public static final int CHANNEL_WIDTH_40MHZ = 3; // 0x3
+    field public static final int CHANNEL_WIDTH_4320MHZ = 8; // 0x8
+    field public static final int CHANNEL_WIDTH_6480MHZ = 9; // 0x9
     field public static final int CHANNEL_WIDTH_80MHZ = 4; // 0x4
     field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 5; // 0x5
+    field public static final int CHANNEL_WIDTH_8640MHZ = 10; // 0xa
     field public static final int CHANNEL_WIDTH_INVALID = 0; // 0x0
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApInfo> CREATOR;
   }
@@ -309,6 +338,7 @@
     method @Deprecated @NonNull public android.net.IpConfiguration getIpConfiguration();
     method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus();
     method @Deprecated @NonNull public String getPrintableSsid();
+    method @Deprecated @NonNull public String getProfileKey();
     method @Deprecated public int getRecentFailureReason();
     method @Deprecated public boolean hasNoInternetAccess();
     method @Deprecated public boolean isEphemeral();
@@ -320,12 +350,19 @@
     field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1
     field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0
     field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2
+    field @Deprecated public static final int RANDOMIZATION_AUTO = 3; // 0x3
+    field @Deprecated public static final int RANDOMIZATION_ENHANCED = 2; // 0x2
     field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0
     field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
     field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
+    field @Deprecated public static final int RECENT_FAILURE_DISCONNECTION_AP_BUSY = 1004; // 0x3ec
+    field @Deprecated public static final int RECENT_FAILURE_MBO_OCE_DISCONNECT = 1001; // 0x3e9
     field @Deprecated public static final int RECENT_FAILURE_NONE = 0; // 0x0
+    field @Deprecated public static final int RECENT_FAILURE_POOR_CHANNEL_CONDITIONS = 1003; // 0x3eb
+    field @Deprecated public static final int RECENT_FAILURE_REFUSED_TEMPORARILY = 1002; // 0x3ea
     field @Deprecated public boolean allowAutojoin;
     field @Deprecated public int carrierId;
+    field @Deprecated public boolean carrierMerged;
     field @Deprecated public String creatorName;
     field @Deprecated public int creatorUid;
     field @Deprecated public boolean fromWifiNetworkSpecifier;
@@ -340,6 +377,7 @@
     field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
     field @Deprecated public boolean requirePmf;
     field @Deprecated public boolean shared;
+    field @Deprecated public int subscriptionId;
     field @Deprecated public boolean useExternalScores;
   }
 
@@ -360,6 +398,8 @@
     method @Deprecated public boolean hasEverConnected();
     field @Deprecated public static final int DISABLED_ASSOCIATION_REJECTION = 1; // 0x1
     field @Deprecated public static final int DISABLED_AUTHENTICATION_FAILURE = 2; // 0x2
+    field @Deprecated public static final int DISABLED_AUTHENTICATION_FAILURE_CARRIER_SPECIFIC = 10; // 0xa
+    field @Deprecated public static final int DISABLED_AUTHENTICATION_FAILURE_GENERIC = 2; // 0x2
     field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5; // 0x5
     field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9; // 0x9
     field @Deprecated public static final int DISABLED_BY_WIFI_MANAGER = 7; // 0x7
@@ -406,11 +446,16 @@
     method @Nullable public String getRequestingPackageName();
     method public double getRetriedTxPacketsPerSecond();
     method public int getScore();
+    method public int getSubscriptionId();
     method public double getSuccessfulRxPacketsPerSecond();
     method public double getSuccessfulTxPacketsPerSecond();
+    method public boolean isCarrierMerged();
     method public boolean isEphemeral();
+    method public boolean isOemPaid();
+    method public boolean isOemPrivate();
     method public boolean isOsuAp();
     method public boolean isPasspointAp();
+    method public boolean isTrusted();
     method @Nullable public static String sanitizeSsid(@Nullable String);
     field public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
     field public static final int INVALID_RSSI = -127; // 0xffffff81
@@ -429,6 +474,8 @@
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
+    method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public int getCoexRestrictions();
+    method @NonNull @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public java.util.Set<android.net.wifi.CoexUnsafeChannel> getCoexUnsafeChannels();
     method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork();
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses();
@@ -436,22 +483,26 @@
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
     method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(@NonNull java.util.List<android.net.wifi.ScanResult>);
+    method public boolean is60GHzBandSupported();
     method public boolean isApMacRandomizationSupported();
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean isCarrierNetworkOffloadEnabled(int, boolean);
     method public boolean isConnectedMacRandomizationSupported();
     method @Deprecated public boolean isDeviceToDeviceRttSupported();
     method public boolean isPortableHotspotSupported();
     method public boolean isVerboseLoggingEnabled();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
+    method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void registerCoexCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.CoexCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
     method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+    method @RequiresPermission(android.Manifest.permission.NETWORK_AIRPLANE_MODE) public void restartWifiSubsystem(@Nullable String);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
     method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration restoreSoftApBackupData(@NonNull byte[]);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
@@ -459,23 +510,29 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setCarrierNetworkOffloadEnabled(int, boolean, boolean);
+    method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS) public void setCoexUnsafeChannels(@NonNull java.util.Set<android.net.wifi.CoexUnsafeChannel>, int);
     method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setPasspointMeteredOverride(@NonNull String, int);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanAlwaysAvailable(boolean);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanThrottleEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setVerboseLoggingEnabled(boolean);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
     method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeResponder(@Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startTemporarilyDisablingAllNonCarrierMergedWifi(int);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspot(@Nullable android.net.wifi.SoftApConfiguration);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopTemporarilyDisablingAllNonCarrierMergedWifi();
+    method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void unregisterCoexCallback(@NonNull android.net.wifi.WifiManager.CoexCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
@@ -489,16 +546,27 @@
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
     field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
+    field public static final int COEX_RESTRICTION_SOFTAP = 2; // 0x2
+    field public static final int COEX_RESTRICTION_WIFI_AWARE = 4; // 0x4
+    field public static final int COEX_RESTRICTION_WIFI_DIRECT = 1; // 0x1
     field public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
     field public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1; // 0x1
     field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
     field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
     field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3; // 0x3
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4; // 0x4
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5; // 0x5
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT = 0; // 0x0
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0; // 0x0
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1; // 0x1
+    field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2; // 0x2
+    field public static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40; // 0x28
     field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
     field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
     field public static final String EXTRA_CHANGE_REASON = "changeReason";
-    field public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
-    field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
+    field @Deprecated public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
+    field @Deprecated public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
     field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
     field public static final String EXTRA_URL = "android.net.wifi.extra.URL";
@@ -506,7 +574,7 @@
     field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
     field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
     field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
-    field public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
+    field @Deprecated public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
     field public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
     field public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
     field public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0; // 0x0
@@ -536,6 +604,11 @@
     method public void onSuccess();
   }
 
+  public abstract static class WifiManager.CoexCallback {
+    ctor public WifiManager.CoexCallback();
+    method public abstract void onCoexUnsafeChannelsChanged();
+  }
+
   public static interface WifiManager.NetworkRequestMatchCallback {
     method public default void onAbort();
     method public default void onMatch(@NonNull java.util.List<android.net.wifi.ScanResult>);
@@ -566,7 +639,9 @@
     method public default void onBlockedClientConnecting(@NonNull android.net.wifi.WifiClient, int);
     method public default void onCapabilityChanged(@NonNull android.net.wifi.SoftApCapability);
     method public default void onConnectedClientsChanged(@NonNull java.util.List<android.net.wifi.WifiClient>);
+    method public default void onConnectedClientsChanged(@NonNull android.net.wifi.SoftApInfo, @NonNull java.util.List<android.net.wifi.WifiClient>);
     method public default void onInfoChanged(@NonNull android.net.wifi.SoftApInfo);
+    method public default void onInfoChanged(@NonNull java.util.List<android.net.wifi.SoftApInfo>);
     method public default void onStateChanged(int, int);
   }
 
@@ -597,10 +672,14 @@
 
   public final class WifiNetworkSuggestion implements android.os.Parcelable {
     method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration();
+    method public boolean isOemPaid();
+    method public boolean isOemPrivate();
   }
 
   public static final class WifiNetworkSuggestion.Builder {
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPaid(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPrivate(boolean);
   }
 
   public class WifiScanner {
@@ -643,6 +722,7 @@
     field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
     field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
     field public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; // 0x6
+    field public static final int WIFI_BAND_60_GHZ = 16; // 0x10
     field public static final int WIFI_BAND_6_GHZ = 8; // 0x8
     field public static final int WIFI_BAND_BOTH = 3; // 0x3
     field public static final int WIFI_BAND_BOTH_WITH_DFS = 7; // 0x7
@@ -785,6 +865,10 @@
     method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]);
   }
 
+  public class WifiAwareManager {
+    method public void enableInstantCommunicationMode(boolean);
+  }
+
   public class WifiAwareSession implements java.lang.AutoCloseable {
     method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, @NonNull byte[], @NonNull byte[]);
   }
@@ -883,6 +967,10 @@
 
 package android.net.wifi.rtt {
 
+  public final class RangingRequest implements android.os.Parcelable {
+    method @NonNull public java.util.List<android.net.wifi.rtt.ResponderConfig> getRttPeers();
+  }
+
   public static final class RangingRequest.Builder {
     method public android.net.wifi.rtt.RangingRequest.Builder addResponder(@NonNull android.net.wifi.rtt.ResponderConfig);
   }
diff --git a/framework/api/system-lint-baseline.txt b/framework/api/system-lint-baseline.txt
index 6547ee8..9a3b66a 100644
--- a/framework/api/system-lint-baseline.txt
+++ b/framework/api/system-lint-baseline.txt
@@ -1,6 +1,13 @@
 // Baseline format: 1.0
 MissingGetterMatchingBuilder: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
-    android.net.wifi.rtt.RangingRequest does not declare a `getResponders()` method matching method android.net.wifi.rtt.RangingRequest.Builder.addResponder(android.net.wifi.rtt.ResponderConfig)
+
+
 
 MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
 
+
+
+MutableBareField: android.net.wifi.WifiConfiguration#carrierMerged:
+
+MutableBareField: android.net.wifi.WifiConfiguration#subscriptionId:
+    Bare field subscriptionId must be marked final, or moved behind accessors if mutable
diff --git a/framework/jarjar-rules.txt b/framework/jarjar-rules.txt
index 7b84d57..2331c2f 100644
--- a/framework/jarjar-rules.txt
+++ b/framework/jarjar-rules.txt
@@ -110,8 +110,6 @@
 rule fi.iki.elonen.** com.android.wifi.x.@0
 
 ## used by both framework-wifi and service-wifi ##
-rule android.content.pm.BaseParceledListSlice* com.android.wifi.x.@0
-rule android.content.pm.ParceledListSlice* com.android.wifi.x.@0
 rule android.os.HandlerExecutor* com.android.wifi.x.@0
 rule android.telephony.Annotation* com.android.wifi.x.@0
 rule com.android.internal.util.AsyncChannel* com.android.wifi.x.@0
diff --git a/framework/java/android/net/wifi/CoexUnsafeChannel.java b/framework/java/android/net/wifi/CoexUnsafeChannel.java
new file mode 100644
index 0000000..3f9efa0
--- /dev/null
+++ b/framework/java/android/net/wifi/CoexUnsafeChannel.java
@@ -0,0 +1,176 @@
+/*
+ * 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;
+
+import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
+import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ;
+import static android.net.wifi.WifiScanner.WIFI_BAND_6_GHZ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Data structure class representing a Wi-Fi channel that would cause interference to/receive
+ * interference from the active cellular channels and should be avoided.
+ *
+ * If {@link #isPowerCapAvailable()} is {@code true}, then a valid power cap value is available
+ * through {@link #getPowerCapDbm()} to be used if this channel cannot be avoided. If {@code false},
+ * then {@link #getPowerCapDbm()} throws an IllegalStateException and the channel will not need to
+ * cap its power.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CoexUnsafeChannel implements Parcelable {
+    private @WifiAnnotations.WifiBandBasic int mBand;
+    private int mChannel;
+    private boolean mIsPowerCapAvailable = false;
+    private int mPowerCapDbm;
+
+    /**
+     * Constructor for a CoexUnsafeChannel with no power cap specified.
+     * @param band One of {@link WifiAnnotations.WifiBandBasic}
+     * @param channel Channel number
+     */
+    public CoexUnsafeChannel(@WifiAnnotations.WifiBandBasic int band, int channel) {
+        mBand = band;
+        mChannel = channel;
+    }
+
+    /**
+     * Constructor for a CoexUnsafeChannel with power cap specified.
+     * @param band One of {@link WifiAnnotations.WifiBandBasic}
+     * @param channel Channel number
+     * @param powerCapDbm Power cap in dBm
+     */
+    public CoexUnsafeChannel(@WifiAnnotations.WifiBandBasic int band, int channel,
+            int powerCapDbm) {
+        mBand = band;
+        mChannel = channel;
+        setPowerCapDbm(powerCapDbm);
+    }
+
+    /** Returns the Wi-Fi band of this channel as one of {@link WifiAnnotations.WifiBandBasic} */
+    public @WifiAnnotations.WifiBandBasic int getBand() {
+        return mBand;
+    }
+
+    /** Returns the channel number of this channel. */
+    public int getChannel() {
+        return mChannel;
+    }
+
+    /** Returns {@code true} if {@link #getPowerCapDbm()} is a valid value, else {@code false} */
+    public boolean isPowerCapAvailable() {
+        return mIsPowerCapAvailable;
+    }
+
+    /**
+     * Returns the power cap of this channel in dBm. Throws IllegalStateException if
+     * {@link #isPowerCapAvailable()} is {@code false}.
+     */
+    public int getPowerCapDbm() {
+        if (!mIsPowerCapAvailable) {
+            throw new IllegalStateException("getPowerCapDbm called but power cap is unavailable");
+        }
+        return mPowerCapDbm;
+    }
+
+    /** Set the power cap of this channel. */
+    public void setPowerCapDbm(int powerCapDbm) {
+        mIsPowerCapAvailable = true;
+        mPowerCapDbm = powerCapDbm;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        CoexUnsafeChannel that = (CoexUnsafeChannel) o;
+        return mBand == that.mBand
+                && mChannel == that.mChannel
+                && mIsPowerCapAvailable == that.mIsPowerCapAvailable
+                && mPowerCapDbm == that.mPowerCapDbm;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mBand, mChannel, mIsPowerCapAvailable, mPowerCapDbm);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sj = new StringBuilder("CoexUnsafeChannel{");
+        sj.append(mChannel);
+        sj.append(", ");
+        if (mBand == WIFI_BAND_24_GHZ) {
+            sj.append("2.4GHz");
+        } else if (mBand == WIFI_BAND_5_GHZ) {
+            sj.append("5GHz");
+        } else if (mBand == WIFI_BAND_6_GHZ) {
+            sj.append("6GHz");
+        } else {
+            sj.append("UNKNOWN BAND");
+        }
+        if (mIsPowerCapAvailable) {
+            sj.append(", ").append(mPowerCapDbm).append("dBm");
+        }
+        sj.append('}');
+        return sj.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mBand);
+        dest.writeInt(mChannel);
+        dest.writeBoolean(mIsPowerCapAvailable);
+        if (mIsPowerCapAvailable) {
+            dest.writeInt(mPowerCapDbm);
+        }
+    }
+
+    /** Implement the Parcelable interface */
+    public static final @NonNull Creator<CoexUnsafeChannel> CREATOR =
+            new Creator<CoexUnsafeChannel>() {
+                public CoexUnsafeChannel createFromParcel(Parcel in) {
+                    final int band = in.readInt();
+                    final int channel = in.readInt();
+                    final boolean isPowerCapAvailable = in.readBoolean();
+                    if (isPowerCapAvailable) {
+                        final int powerCapDbm = in.readInt();
+                        return new CoexUnsafeChannel(band, channel, powerCapDbm);
+                    }
+                    return new CoexUnsafeChannel(band, channel);
+                }
+
+                public CoexUnsafeChannel[] newArray(int size) {
+                    return new CoexUnsafeChannel[size];
+                }
+            };
+}
diff --git a/framework/java/android/net/wifi/EasyConnectStatusCallback.java b/framework/java/android/net/wifi/EasyConnectStatusCallback.java
index 6c2e6dd..ee70255 100644
--- a/framework/java/android/net/wifi/EasyConnectStatusCallback.java
+++ b/framework/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -161,6 +161,11 @@
      */
     public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12;
 
+    /**
+     * Easy Connect Failure event: System failed to generate DPP URI.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_URI_GENERATION = -13;
+
     /** @hide */
     @IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
             EASY_CONNECT_EVENT_FAILURE_INVALID_URI,
@@ -175,6 +180,7 @@
             EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
             EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION,
             EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION,
+            EASY_CONNECT_EVENT_FAILURE_URI_GENERATION,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EasyConnectFailureStatusCode {
@@ -264,4 +270,17 @@
      */
     @SystemApi
     public abstract void onProgress(@EasyConnectProgressStatusCode int code);
+
+    /**
+     * Called when local Easy Connect Responder successfully generates a DPP URI from
+     * the supplicant. This callback is the first successful outcome
+     * of a Easy Connect Responder flow starting with
+     * {@link WifiManager#startEasyConnectAsEnrolleeResponder(String, int, Executor,
+     * EasyConnectStatusCallback)} .
+     *
+     * @param uri DPP URI from the supplicant.
+     * @hide
+     */
+    @SystemApi
+    public void onBootstrapUriGenerated(@NonNull String uri) {};
 }
diff --git a/framework/java/android/net/wifi/ITxPacketCountListener.aidl b/framework/java/android/net/wifi/ICoexCallback.aidl
similarity index 69%
copy from framework/java/android/net/wifi/ITxPacketCountListener.aidl
copy to framework/java/android/net/wifi/ICoexCallback.aidl
index 9105bd0..89e4c4b 100644
--- a/framework/java/android/net/wifi/ITxPacketCountListener.aidl
+++ b/framework/java/android/net/wifi/ICoexCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -17,12 +17,10 @@
 package android.net.wifi;
 
 /**
- * Interface for tx packet counter callback.
- * @deprecated no longer used, remove once removed from BaseWifiService
+ * Interface for Wi-Fi/cellular coex callback.
  * @hide
  */
-oneway interface ITxPacketCountListener
+oneway interface ICoexCallback
 {
-    void onSuccess(int count);
-    void onFailure(int reason);
+    void onCoexUnsafeChannelsChanged();
 }
diff --git a/framework/java/android/net/wifi/IDppCallback.aidl b/framework/java/android/net/wifi/IDppCallback.aidl
index d7a958a..dcbe846 100644
--- a/framework/java/android/net/wifi/IDppCallback.aidl
+++ b/framework/java/android/net/wifi/IDppCallback.aidl
@@ -45,4 +45,10 @@
      * to show progress.
      */
     void onProgress(int status);
+
+    /**
+     * Called when local DPP Responder successfully generates a URI.
+     */
+    void onBootstrapUriGenerated(String uri);
+
 }
diff --git a/framework/java/android/net/wifi/ISoftApCallback.aidl b/framework/java/android/net/wifi/ISoftApCallback.aidl
index f81bcb9..3db0a5d 100644
--- a/framework/java/android/net/wifi/ISoftApCallback.aidl
+++ b/framework/java/android/net/wifi/ISoftApCallback.aidl
@@ -40,19 +40,16 @@
     void onStateChanged(int state, int failureReason);
 
     /**
-     * Service to manager callback providing connected client's information.
+     * Service to manager callback providing informations of softap.
      *
-     * @param clients the currently connected clients
+     * @param infos The currently {@link SoftApInfo} in each AP instance.
+     * @param clients The currently connected clients in each AP instance.
+     * @param isBridged whether or not the current AP enabled on bridged mode.
+     * @param isRegistration whether or not the callbackk was triggered when register.
      */
-    void onConnectedClientsChanged(in List<WifiClient> clients);
-
-    /**
-     * Service to manager callback providing information of softap.
-     *
-     * @param softApInfo is the softap information. {@link SoftApInfo}
-     */
-    void onInfoChanged(in SoftApInfo softApInfo);
-
+    void onConnectedClientsOrInfoChanged(in Map<String, SoftApInfo> infos,
+            in Map<String, List<WifiClient>> clients, boolean isBridged,
+	    boolean isRegistration);
 
     /**
      * Service to manager callback providing capability of softap.
diff --git a/framework/java/android/net/wifi/ITxPacketCountListener.aidl b/framework/java/android/net/wifi/ISuggestionUserApprovalStatusListener.aidl
similarity index 69%
rename from framework/java/android/net/wifi/ITxPacketCountListener.aidl
rename to framework/java/android/net/wifi/ISuggestionUserApprovalStatusListener.aidl
index 9105bd0..5aa3a90 100644
--- a/framework/java/android/net/wifi/ITxPacketCountListener.aidl
+++ b/framework/java/android/net/wifi/ISuggestionUserApprovalStatusListener.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -17,12 +17,11 @@
 package android.net.wifi;
 
 /**
- * Interface for tx packet counter callback.
- * @deprecated no longer used, remove once removed from BaseWifiService
+ * Interface for suggestion user approval status listener.
+ *
  * @hide
  */
-oneway interface ITxPacketCountListener
+oneway interface ISuggestionUserApprovalStatusListener
 {
-    void onSuccess(int count);
-    void onFailure(int reason);
+   void onUserApprovalStatusChange();
 }
diff --git a/framework/java/android/net/wifi/IWifiManager.aidl b/framework/java/android/net/wifi/IWifiManager.aidl
index 3f79364..23f47ef 100644
--- a/framework/java/android/net/wifi/IWifiManager.aidl
+++ b/framework/java/android/net/wifi/IWifiManager.aidl
@@ -16,15 +16,15 @@
 
 package android.net.wifi;
 
-import android.content.pm.ParceledListSlice;
-
 import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 
 import android.net.DhcpInfo;
 import android.net.Network;
+import android.net.wifi.CoexUnsafeChannel;
 import android.net.wifi.IActionListener;
+import android.net.wifi.ICoexCallback;
 import android.net.wifi.IDppCallback;
 import android.net.wifi.ILocalOnlyHotspotCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
@@ -33,6 +33,7 @@
 import android.net.wifi.IScanResultsCallback;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ISuggestionConnectionStatusListener;
+import android.net.wifi.ISuggestionUserApprovalStatusListener;
 import android.net.wifi.ITrafficStateCallback;
 import android.net.wifi.IWifiConnectedNetworkScorer;
 import android.net.wifi.ScanResult;
@@ -45,6 +46,8 @@
 import android.os.ResultReceiver;
 import android.os.WorkSource;
 
+import com.android.modules.utils.ParceledListSlice;
+
 /**
  * Interface that allows controlling and querying Wi-Fi connectivity.
  *
@@ -80,8 +83,6 @@
 
     int matchProviderWithCurrentNetwork(String fqdn);
 
-    void deauthenticateNetwork(long holdoff, boolean ess);
-
     boolean removeNetwork(int netId, String packageName);
 
     boolean enableNetwork(int netId, boolean disableOthers, String packageName);
@@ -120,11 +121,13 @@
 
     boolean is6GHzBandSupported();
 
+    boolean is60GHzBandSupported();
+
     boolean isWifiStandardSupported(int standard);
 
     DhcpInfo getDhcpInfo();
 
-    void setScanAlwaysAvailable(boolean isAvailable);
+    void setScanAlwaysAvailable(boolean isAvailable, String packageName);
 
     boolean isScanAlwaysAvailable();
 
@@ -144,9 +147,21 @@
 
     void updateInterfaceIpState(String ifaceName, int mode);
 
-    boolean startSoftAp(in WifiConfiguration wifiConfig);
+    boolean isDefaultCoexAlgorithmEnabled();
 
-    boolean startTetheredHotspot(in SoftApConfiguration softApConfig);
+    void setCoexUnsafeChannels(in List<CoexUnsafeChannel> unsafeChannels, int mandatoryRestrictions);
+
+    List<CoexUnsafeChannel> getCoexUnsafeChannels();
+
+    int getCoexRestrictions();
+
+    void registerCoexCallback(in ICoexCallback callback);
+
+    void unregisterCoexCallback(in ICoexCallback callback);
+
+    boolean startSoftAp(in WifiConfiguration wifiConfig, String packageName);
+
+    boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName);
 
     boolean stopSoftAp();
 
@@ -235,15 +250,18 @@
     void startDppAsEnrolleeInitiator(in IBinder binder, in String configuratorUri,
         in IDppCallback callback);
 
+    void startDppAsEnrolleeResponder(in IBinder binder, in String deviceInfo, int curve,
+        in IDppCallback callback);
+
     void stopDppSession();
 
     void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec);
 
-    oneway void connect(in WifiConfiguration config, int netId, in IBinder binder, in IActionListener listener, int callbackIdentifier);
+    oneway void connect(in WifiConfiguration config, int netId, in IActionListener listener);
 
-    oneway void save(in WifiConfiguration config, in IBinder binder, in IActionListener listener, int callbackIdentifier);
+    oneway void save(in WifiConfiguration config, in IActionListener listener);
 
-    oneway void forget(int netId, in IBinder binder, in IActionListener listener, int callbackIdentifier);
+    oneway void forget(int netId, in IActionListener listener);
 
     void registerScanResultsCallback(in IScanResultsCallback callback);
 
@@ -275,4 +293,20 @@
     void setAutoWakeupEnabled(boolean enable);
 
     boolean isAutoWakeupEnabled();
+
+    int getNetworkSuggestionUserApprovalStatus(String packageName);
+
+    void startTemporarilyDisablingAllNonCarrierMergedWifi(int subId);
+
+    void stopTemporarilyDisablingAllNonCarrierMergedWifi();
+
+    void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged, boolean enabled);
+
+    boolean isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged);
+
+    void restartWifiSubsystem(String reason);
+
+    boolean addSuggestionUserApprovalStatusListener(in IBinder binder, in ISuggestionUserApprovalStatusListener listener, int listenerIdentifier, String packageName, String featureId);
+
+    void removeSuggestionUserApprovalStatusListener(int listenerIdentifier, String packageName);
 }
diff --git a/framework/java/android/net/wifi/ScanResult.java b/framework/java/android/net/wifi/ScanResult.java
index 5589bd1..9f8ecf1 100644
--- a/framework/java/android/net/wifi/ScanResult.java
+++ b/framework/java/android/net/wifi/ScanResult.java
@@ -82,6 +82,12 @@
     public String capabilities;
 
     /**
+     * The interface name on which the scan result was received.
+     * @hide
+     */
+    public String ifaceName;
+
+    /**
      * @hide
      * No security protocol.
      */
@@ -314,6 +320,11 @@
     public static final int WIFI_STANDARD_11AX = 6;
 
     /**
+     * Wi-Fi 802.11ad/ay
+     */
+    public static final int WIFI_STANDARD_11AD = 7;
+
+    /**
      * AP wifi standard.
      */
     private @WifiStandard int mWifiStandard;
@@ -346,6 +357,8 @@
                 return "11ac";
             case WIFI_STANDARD_11AX:
                 return "11ax";
+            case WIFI_STANDARD_11AD:
+                return "11ad";
             case WIFI_STANDARD_UNKNOWN:
                 return "unknown";
         }
@@ -596,6 +609,27 @@
     public static final int BAND_6_GHZ_OP_CLASS_136_CH_2_FREQ_MHZ = 5935;
 
     /**
+     * 60 GHz band first channel number
+     * @hide
+     */
+    public static final int BAND_60_GHZ_FIRST_CH_NUM = 1;
+    /**
+     * 60 GHz band last channel number
+     * @hide
+     */
+    public static final int BAND_60_GHZ_LAST_CH_NUM = 6;
+    /**
+     * 60 GHz band frequency of first channel in MHz
+     * @hide
+     */
+    public static final int BAND_60_GHZ_START_FREQ_MHZ = 58320;
+    /**
+     * 60 GHz band frequency of last channel in MHz
+     * @hide
+     */
+    public static final int BAND_60_GHZ_END_FREQ_MHZ = 70200;
+
+    /**
      * Utility function to check if a frequency within 2.4 GHz band
      * @param freqMhz frequency in MHz
      * @return true if within 2.4GHz, false otherwise
@@ -632,6 +666,17 @@
     }
 
     /**
+     * Utility function to check if a frequency within 60 GHz band
+     * @param freqMhz
+     * @return true if within 60GHz, false otherwise
+     *
+     * @hide
+     */
+    public static boolean is60GHz(int freqMhz) {
+        return freqMhz >= BAND_60_GHZ_START_FREQ_MHZ && freqMhz <= BAND_60_GHZ_END_FREQ_MHZ;
+    }
+
+    /**
      * Utility function to convert channel number/band to frequency in MHz
      * @param channel number to convert
      * @param band of channel to convert
@@ -667,6 +712,13 @@
                 return UNSPECIFIED;
             }
         }
+        if (band == WifiScanner.WIFI_BAND_60_GHZ) {
+            if (channel >= BAND_60_GHZ_FIRST_CH_NUM && channel <= BAND_60_GHZ_LAST_CH_NUM) {
+                return ((channel - BAND_60_GHZ_FIRST_CH_NUM) * 2160) + BAND_60_GHZ_START_FREQ_MHZ;
+            } else {
+                return UNSPECIFIED;
+            }
+        }
         return UNSPECIFIED;
     }
 
@@ -717,6 +769,13 @@
     }
 
     /**
+     * @hide
+     */
+    public boolean is60GHz() {
+        return ScanResult.is60GHz(frequency);
+    }
+
+    /**
      *  @hide
      * anqp lines from supplicant BSS response
      */
@@ -955,6 +1014,7 @@
             flags = source.flags;
             radioChainInfos = source.radioChainInfos;
             this.mWifiStandard = source.mWifiStandard;
+            this.ifaceName = source.ifaceName;
         }
     }
 
@@ -993,6 +1053,7 @@
         sb.append(", 80211mcResponder: ");
         sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
         sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos));
+        sb.append(", interface name: ").append(ifaceName);
         return sb.toString();
     }
 
@@ -1072,6 +1133,7 @@
         } else {
             dest.writeInt(0);
         }
+        dest.writeString((ifaceName != null) ? ifaceName.toString() : "");
     }
 
     /** Implement the Parcelable interface */
@@ -1150,6 +1212,7 @@
                         sr.radioChainInfos[i].level = in.readInt();
                     }
                 }
+                sr.ifaceName = in.readString();
                 return sr;
             }
 
diff --git a/framework/java/android/net/wifi/SecurityParams.java b/framework/java/android/net/wifi/SecurityParams.java
new file mode 100644
index 0000000..8ee2ea0
--- /dev/null
+++ b/framework/java/android/net/wifi/SecurityParams.java
@@ -0,0 +1,888 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.GroupCipher;
+import android.net.wifi.WifiConfiguration.GroupMgmtCipher;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiConfiguration.PairwiseCipher;
+import android.net.wifi.WifiConfiguration.Protocol;
+import android.net.wifi.WifiConfiguration.SecurityType;
+import android.net.wifi.WifiConfiguration.SuiteBCipher;
+import android.os.Parcel;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.BitSet;
+import java.util.Objects;
+
+/**
+ * A class representing a security configuration.
+ * @hide
+ */
+public class SecurityParams {
+    private static final String TAG = "SecurityParams";
+
+    /** Passpoint Release 1 */
+    public static final int PASSPOINT_R1 = 1;
+
+    /** Passpoint Release 2 */
+    public static final int PASSPOINT_R2 = 2;
+
+    /** Passpoint Release 3 */
+    public static final int PASSPOINT_R3 = 3;
+
+    @IntDef(prefix = { "PASSPOINT_" }, value = {
+        PASSPOINT_R1,
+        PASSPOINT_R2,
+        PASSPOINT_R3,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PasspointRelease {}
+
+    private @SecurityType int mSecurityType = WifiConfiguration.SECURITY_TYPE_PSK;
+
+    /**
+     * This indicates that this security type is enabled or disabled.
+     * Ex. While receiving Transition Disable Indication, older
+     * security should be disabled.
+     */
+    private boolean mEnabled = true;
+
+    /**
+     * The set of key management protocols supported by this configuration.
+     * See {@link KeyMgmt} for descriptions of the values.
+     * This is set automatically based on the security type.
+     */
+    private BitSet mAllowedKeyManagement = new BitSet();
+
+    /**
+     * The set of security protocols supported by this configuration.
+     * See {@link Protocol} for descriptions of the values.
+     * This is set automatically based on the security type.
+     */
+    private BitSet mAllowedProtocols = new BitSet();
+
+    /**
+     * The set of authentication protocols supported by this configuration.
+     * See {@link AuthAlgorithm} for descriptions of the values.
+     * This is set automatically based on the security type.
+     */
+    private BitSet mAllowedAuthAlgorithms = new BitSet();
+
+    /**
+     * The set of pairwise ciphers for WPA supported by this configuration.
+     * See {@link PairwiseCipher} for descriptions of the values.
+     * This is set automatically based on the security type.
+     */
+    private BitSet mAllowedPairwiseCiphers = new BitSet();
+
+    /**
+     * The set of group ciphers supported by this configuration.
+     * See {@link GroupCipher} for descriptions of the values.
+     * This is set automatically based on the security type.
+     */
+    private BitSet mAllowedGroupCiphers = new BitSet();
+
+    /**
+     * The set of group management ciphers supported by this configuration.
+     * See {@link GroupMgmtCipher} for descriptions of the values.
+     */
+    private BitSet mAllowedGroupManagementCiphers = new BitSet();
+
+    /**
+     * The set of SuiteB ciphers supported by this configuration.
+     * To be used for WPA3-Enterprise mode. Set automatically by the framework based on the
+     * certificate type that is used in this configuration.
+     */
+    private BitSet mAllowedSuiteBCiphers = new BitSet();
+
+    /**
+     * True if the network requires Protected Management Frames (PMF), false otherwise.
+     */
+    private boolean mRequirePmf = false;
+
+    private @PasspointRelease int mPasspointRelease = PASSPOINT_R2;
+
+    /** Indicate that this SAE security type only accepts H2E (Hash-to-Element) mode. */
+    private boolean mIsSaeH2eOnlyMode = false;
+
+    /** Indicate that this SAE security type only accepts PK (Public Key) mode. */
+    private boolean mIsSaePkOnlyMode = false;
+
+    /** Indicate whether this is added by auto-upgrade or not. */
+    private boolean mIsAddedByAutoUpgrade = false;
+
+    /** Constructor */
+    private SecurityParams() {
+    }
+
+    /** Copy constructor */
+    public SecurityParams(@NonNull SecurityParams source) {
+        this.mSecurityType = source.mSecurityType;
+        this.mEnabled = source.mEnabled;
+        this.mAllowedKeyManagement = (BitSet) source.mAllowedKeyManagement.clone();
+        this.mAllowedProtocols = (BitSet) source.mAllowedProtocols.clone();
+        this.mAllowedAuthAlgorithms = (BitSet) source.mAllowedAuthAlgorithms.clone();
+        this.mAllowedPairwiseCiphers = (BitSet) source.mAllowedPairwiseCiphers.clone();
+        this.mAllowedGroupCiphers = (BitSet) source.mAllowedGroupCiphers.clone();
+        this.mAllowedGroupManagementCiphers =
+                (BitSet) source.mAllowedGroupManagementCiphers.clone();
+        this.mAllowedSuiteBCiphers =
+                (BitSet) source.mAllowedSuiteBCiphers.clone();
+        this.mRequirePmf = source.mRequirePmf;
+        this.mIsSaeH2eOnlyMode = source.mIsSaeH2eOnlyMode;
+        this.mIsSaePkOnlyMode = source.mIsSaePkOnlyMode;
+        this.mIsAddedByAutoUpgrade = source.mIsAddedByAutoUpgrade;
+    }
+
+    @Override
+    public boolean equals(Object thatObject) {
+        if (this == thatObject) {
+            return true;
+        }
+        if (!(thatObject instanceof SecurityParams)) {
+            return false;
+        }
+        SecurityParams that = (SecurityParams) thatObject;
+
+        if (this.mSecurityType != that.mSecurityType) return false;
+        if (this.mEnabled != that.mEnabled) return false;
+        if (!this.mAllowedKeyManagement.equals(that.mAllowedKeyManagement)) return false;
+        if (!this.mAllowedProtocols.equals(that.mAllowedProtocols)) return false;
+        if (!this.mAllowedAuthAlgorithms.equals(that.mAllowedAuthAlgorithms)) return false;
+        if (!this.mAllowedPairwiseCiphers.equals(that.mAllowedPairwiseCiphers)) return false;
+        if (!this.mAllowedGroupCiphers.equals(that.mAllowedGroupCiphers)) return false;
+        if (!this.mAllowedGroupManagementCiphers.equals(that.mAllowedGroupManagementCiphers)) {
+            return false;
+        }
+        if (!this.mAllowedSuiteBCiphers.equals(that.mAllowedSuiteBCiphers)) return false;
+        if (this.mRequirePmf != that.mRequirePmf) return false;
+        if (this.mIsSaeH2eOnlyMode != that.mIsSaeH2eOnlyMode) return false;
+        if (this.mIsSaePkOnlyMode != that.mIsSaePkOnlyMode) return false;
+        if (this.mIsAddedByAutoUpgrade != that.mIsAddedByAutoUpgrade) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSecurityType, mEnabled,
+                mAllowedKeyManagement, mAllowedProtocols, mAllowedAuthAlgorithms,
+                mAllowedPairwiseCiphers, mAllowedGroupCiphers, mAllowedGroupManagementCiphers,
+                mAllowedSuiteBCiphers, mRequirePmf,
+                mIsSaeH2eOnlyMode, mIsSaePkOnlyMode, mIsAddedByAutoUpgrade);
+    }
+
+    /**
+     * Get the security type of this params.
+     *
+     * @return The security type defined in {@link WifiConfiguration}.
+     */
+    public @SecurityType int getSecurityType() {
+        return mSecurityType;
+    }
+
+    /**
+     * Check the security type of this params.
+     *
+     * @param type the testing security type.
+     * @return true if this is for the corresponiding type.
+     */
+    public boolean isSecurityType(@SecurityType int type) {
+        return type == mSecurityType;
+    }
+
+    /**
+     * Check whether the security of given params is the same as this one.
+     *
+     * @param params the testing security params.
+     * @return true if their security types are the same.
+     */
+    public boolean isSameSecurityType(SecurityParams params) {
+        return params.mSecurityType == mSecurityType;
+    }
+
+    /**
+     * Update security params to legacy WifiConfiguration object.
+     *
+     * @param config the target configuration.
+     */
+    public void updateLegacyWifiConfiguration(WifiConfiguration config) {
+        config.allowedKeyManagement = (BitSet) mAllowedKeyManagement.clone();
+        config.allowedProtocols = (BitSet) mAllowedProtocols.clone();
+        config.allowedAuthAlgorithms = (BitSet) mAllowedAuthAlgorithms.clone();
+        config.allowedPairwiseCiphers = (BitSet) mAllowedPairwiseCiphers.clone();
+        config.allowedGroupCiphers = (BitSet) mAllowedGroupCiphers.clone();
+        config.allowedGroupManagementCiphers = (BitSet) mAllowedGroupManagementCiphers.clone();
+        config.allowedSuiteBCiphers = (BitSet) mAllowedSuiteBCiphers.clone();
+        config.requirePmf = mRequirePmf;
+    }
+
+    /**
+     * Set this params enabled.
+     *
+     * @param enable enable a specific security type.
+     */
+    public void setEnabled(boolean enable) {
+        mEnabled = enable;
+    }
+
+    /**
+     * Indicate this params is enabled or not.
+     */
+    public boolean isEnabled() {
+        return mEnabled;
+    }
+
+    /**
+     * Set the supporting Fast Initial Link Set-up (FILS) key management.
+     *
+     * FILS can be applied to all security types.
+     * @param enableFilsSha256 Enable FILS SHA256.
+     * @param enableFilsSha384 Enable FILS SHA256.
+     */
+    public void enableFils(boolean enableFilsSha256, boolean enableFilsSha384) {
+        if (enableFilsSha256) {
+            mAllowedKeyManagement.set(KeyMgmt.FILS_SHA256);
+        }
+
+        if (enableFilsSha384) {
+            mAllowedKeyManagement.set(KeyMgmt.FILS_SHA384);
+        }
+    }
+
+    /**
+     * Get the copy of allowed key management.
+     */
+    public BitSet getAllowedKeyManagement() {
+        return (BitSet) mAllowedKeyManagement.clone();
+    }
+
+    /**
+     * Get the copy of allowed protocols.
+     */
+    public BitSet getAllowedProtocols() {
+        return (BitSet) mAllowedProtocols.clone();
+    }
+
+    /**
+     * Get the copy of allowed auth algorithms.
+     */
+    public BitSet getAllowedAuthAlgorithms() {
+        return (BitSet) mAllowedAuthAlgorithms.clone();
+    }
+
+    /**
+     * Get the copy of allowed pairwise ciphers.
+     */
+    public BitSet getAllowedPairwiseCiphers() {
+        return (BitSet) mAllowedPairwiseCiphers.clone();
+    }
+
+    /**
+     * Get the copy of allowed group ciphers.
+     */
+    public BitSet getAllowedGroupCiphers() {
+        return (BitSet) mAllowedGroupCiphers.clone();
+    }
+
+    /**
+     * Get the copy of allowed group management ciphers.
+     */
+    public BitSet getAllowedGroupManagementCiphers() {
+        return (BitSet) mAllowedGroupManagementCiphers.clone();
+    }
+
+    /**
+     * Enable Suite-B ciphers.
+     *
+     * @param enableEcdheEcdsa enable Diffie-Hellman with Elliptic Curve ECDSA cipher support.
+     * @param enableEcdheRsa enable Diffie-Hellman with RSA cipher support.
+     */
+    public void enableSuiteBCiphers(boolean enableEcdheEcdsa, boolean enableEcdheRsa) {
+        if (enableEcdheEcdsa) {
+            mAllowedSuiteBCiphers.set(SuiteBCipher.ECDHE_ECDSA);
+        } else {
+            mAllowedSuiteBCiphers.clear(SuiteBCipher.ECDHE_ECDSA);
+        }
+
+        if (enableEcdheRsa) {
+            mAllowedSuiteBCiphers.set(SuiteBCipher.ECDHE_RSA);
+        } else {
+            mAllowedSuiteBCiphers.clear(SuiteBCipher.ECDHE_RSA);
+        }
+    }
+
+    /**
+     * Get the copy of allowed suite-b ciphers.
+     */
+    public BitSet getAllowedSuiteBCiphers() {
+        return (BitSet) mAllowedSuiteBCiphers.clone();
+    }
+
+    /**
+     * Indicate PMF is required or not.
+     */
+    public boolean isRequirePmf() {
+        return mRequirePmf;
+    }
+
+    /**
+     * Indicate that this is open security type.
+     */
+    public boolean isOpenSecurityType() {
+        return isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN)
+                || isSecurityType(WifiConfiguration.SECURITY_TYPE_OWE);
+    }
+
+    /**
+     * Indicate that this is enterprise security type.
+     */
+    public boolean isEnterpriseSecurityType() {
+        return mAllowedKeyManagement.get(KeyMgmt.WPA_EAP)
+                || mAllowedKeyManagement.get(KeyMgmt.IEEE8021X)
+                || mAllowedKeyManagement.get(KeyMgmt.SUITE_B_192)
+                || mAllowedKeyManagement.get(KeyMgmt.WAPI_CERT);
+    }
+
+    /**
+     * Enable Hash-to-Element only mode.
+     *
+     * @param enable set H2E only mode enabled or not.
+     */
+    public void enableSaeH2eOnlyMode(boolean enable) {
+        mIsSaeH2eOnlyMode = enable;
+    }
+
+    /**
+     * Indicate whether this params is H2E only mode.
+     *
+     * @return true if this is H2E only mode params.
+     */
+    public boolean isSaeH2eOnlyMode() {
+        return mIsSaeH2eOnlyMode;
+    }
+    /**
+     * Enable Pubilc-Key only mode.
+     *
+     * @param enable set PK only mode enabled or not.
+     */
+    public void enableSaePkOnlyMode(boolean enable) {
+        mIsSaePkOnlyMode = enable;
+    }
+
+    /**
+     * Indicate whether this params is PK only mode.
+     *
+     * @return true if this is PK only mode params.
+     */
+    public boolean isSaePkOnlyMode() {
+        return mIsSaePkOnlyMode;
+    }
+
+    /**
+     * Set whether this is added by auto-upgrade.
+     *
+     * @param addedByAutoUpgrade true if added by auto-upgrade.
+     */
+    public void setIsAddedByAutoUpgrade(boolean addedByAutoUpgrade) {
+        mIsAddedByAutoUpgrade = addedByAutoUpgrade;
+    }
+
+    /**
+     * Indicate whether this is added by auto-upgrade or not.
+     *
+     * @return true if added by auto-upgrade; otherwise, false.
+     */
+    public boolean isAddedByAutoUpgrade() {
+        return mIsAddedByAutoUpgrade;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append("Security Parameters:\n");
+        sbuf.append(" Type: ").append(mSecurityType).append("\n");
+        sbuf.append(" Enabled: ").append(mEnabled).append("\n");
+        sbuf.append(" KeyMgmt:");
+        for (int k = 0; k < mAllowedKeyManagement.size(); k++) {
+            if (mAllowedKeyManagement.get(k)) {
+                sbuf.append(" ");
+                if (k < KeyMgmt.strings.length) {
+                    sbuf.append(KeyMgmt.strings[k]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n');
+        sbuf.append(" Protocols:");
+        for (int p = 0; p < mAllowedProtocols.size(); p++) {
+            if (mAllowedProtocols.get(p)) {
+                sbuf.append(" ");
+                if (p < Protocol.strings.length) {
+                    sbuf.append(Protocol.strings[p]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n');
+        sbuf.append(" AuthAlgorithms:");
+        for (int a = 0; a < mAllowedAuthAlgorithms.size(); a++) {
+            if (mAllowedAuthAlgorithms.get(a)) {
+                sbuf.append(" ");
+                if (a < AuthAlgorithm.strings.length) {
+                    sbuf.append(AuthAlgorithm.strings[a]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n');
+        sbuf.append(" PairwiseCiphers:");
+        for (int pc = 0; pc < mAllowedPairwiseCiphers.size(); pc++) {
+            if (mAllowedPairwiseCiphers.get(pc)) {
+                sbuf.append(" ");
+                if (pc < PairwiseCipher.strings.length) {
+                    sbuf.append(PairwiseCipher.strings[pc]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n');
+        sbuf.append(" GroupCiphers:");
+        for (int gc = 0; gc < mAllowedGroupCiphers.size(); gc++) {
+            if (mAllowedGroupCiphers.get(gc)) {
+                sbuf.append(" ");
+                if (gc < GroupCipher.strings.length) {
+                    sbuf.append(GroupCipher.strings[gc]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n');
+        sbuf.append(" GroupMgmtCiphers:");
+        for (int gmc = 0; gmc < mAllowedGroupManagementCiphers.size(); gmc++) {
+            if (mAllowedGroupManagementCiphers.get(gmc)) {
+                sbuf.append(" ");
+                if (gmc < GroupMgmtCipher.strings.length) {
+                    sbuf.append(GroupMgmtCipher.strings[gmc]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n');
+        sbuf.append(" SuiteBCiphers:");
+        for (int sbc = 0; sbc < mAllowedSuiteBCiphers.size(); sbc++) {
+            if (mAllowedSuiteBCiphers.get(sbc)) {
+                sbuf.append(" ");
+                if (sbc < SuiteBCipher.strings.length) {
+                    sbuf.append(SuiteBCipher.strings[sbc]);
+                } else {
+                    sbuf.append("??");
+                }
+            }
+        }
+        sbuf.append('\n');
+        sbuf.append(" RequirePmf: ").append(mRequirePmf).append('\n');
+        sbuf.append(" IsAddedByAutoUpgrade: ").append(mIsAddedByAutoUpgrade).append("\n");
+        sbuf.append(" IsSaeH2eOnlyMode: ").append(mIsSaeH2eOnlyMode).append("\n");
+        sbuf.append(" IsSaePkOnlyMode: ").append(mIsSaePkOnlyMode).append("\n");
+        return sbuf.toString();
+    }
+
+    private static BitSet readBitSet(Parcel src) {
+        int cardinality = src.readInt();
+
+        BitSet set = new BitSet();
+        for (int i = 0; i < cardinality; i++) {
+            set.set(src.readInt());
+        }
+
+        return set;
+    }
+
+    private static void writeBitSet(Parcel dest, BitSet set) {
+        int nextSetBit = -1;
+
+        dest.writeInt(set.cardinality());
+
+        while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
+            dest.writeInt(nextSetBit);
+        }
+    }
+
+    /** Write this object to the parcel. */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSecurityType);
+        dest.writeBoolean(mEnabled);
+        writeBitSet(dest, mAllowedKeyManagement);
+        writeBitSet(dest, mAllowedProtocols);
+        writeBitSet(dest, mAllowedAuthAlgorithms);
+        writeBitSet(dest, mAllowedPairwiseCiphers);
+        writeBitSet(dest, mAllowedGroupCiphers);
+        writeBitSet(dest, mAllowedGroupManagementCiphers);
+        writeBitSet(dest, mAllowedSuiteBCiphers);
+        dest.writeBoolean(mRequirePmf);
+        dest.writeBoolean(mIsAddedByAutoUpgrade);
+        dest.writeBoolean(mIsSaeH2eOnlyMode);
+        dest.writeBoolean(mIsSaePkOnlyMode);
+
+    }
+
+    /** Create a SecurityParams object from the parcel. */
+    public static final @NonNull SecurityParams createFromParcel(Parcel in) {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = in.readInt();
+        params.mEnabled = in.readBoolean();
+        params.mAllowedKeyManagement = readBitSet(in);
+        params.mAllowedProtocols = readBitSet(in);
+        params.mAllowedAuthAlgorithms = readBitSet(in);
+        params.mAllowedPairwiseCiphers = readBitSet(in);
+        params.mAllowedGroupCiphers = readBitSet(in);
+        params.mAllowedGroupManagementCiphers = readBitSet(in);
+        params.mAllowedSuiteBCiphers = readBitSet(in);
+        params.mRequirePmf = in.readBoolean();
+        params.mIsAddedByAutoUpgrade = in.readBoolean();
+        params.mIsSaeH2eOnlyMode = in.readBoolean();
+        params.mIsSaePkOnlyMode = in.readBoolean();
+        return params;
+    }
+
+    /**
+     * Create a params according to the security type.
+     *
+     * @param securityType One of the following security types:
+     * {@link WifiConfiguration#SECURITY_TYPE_OPEN},
+     * {@link WifiConfiguration#SECURITY_TYPE_WEP},
+     * {@link WifiConfiguration#SECURITY_TYPE_PSK},
+     * {@link WifiConfiguration#SECURITY_TYPE_EAP},
+     * {@link WifiConfiguration#SECURITY_TYPE_SAE},
+     * {@link WifiConfiguration#SECURITY_TYPE_OWE},
+     * {@link WifiConfiguration#SECURITY_TYPE_WAPI_PSK},
+     * {@link WifiConfiguration#SECURITY_TYPE_WAPI_CERT},
+     * {@link WifiConfiguration#SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+     * {@link WifiConfiguration#SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT},
+     *
+     * @return the corresponding security params if the security type is valid;
+     *         otherwise, throw IllegalArgumentException.
+     */
+    public static @NonNull SecurityParams createSecurityParamsBySecurityType(
+            @WifiConfiguration.SecurityType int securityType) {
+        switch (securityType) {
+            case WifiConfiguration.SECURITY_TYPE_OPEN:
+                return createOpenParams();
+            case WifiConfiguration.SECURITY_TYPE_WEP:
+                return createWepParams();
+            case WifiConfiguration.SECURITY_TYPE_PSK:
+                return createWpaWpa2PersonalParams();
+            case WifiConfiguration.SECURITY_TYPE_EAP:
+                return createWpaWpa2EnterpriseParams();
+            case WifiConfiguration.SECURITY_TYPE_SAE:
+                return createWpa3PersonalParams();
+            // The value of {@link WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B} is the same as
+            // {@link #WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, remove it
+            // to avoid duplicate case label errors.
+            case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
+                return createWpa3Enterprise192BitParams();
+            case WifiConfiguration.SECURITY_TYPE_OWE:
+                return createEnhancedOpenParams();
+            case WifiConfiguration.SECURITY_TYPE_WAPI_PSK:
+                return createWapiPskParams();
+            case WifiConfiguration.SECURITY_TYPE_WAPI_CERT:
+                return createWapiCertParams();
+            case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
+                return createWpa3EnterpriseParams();
+            case WifiConfiguration.SECURITY_TYPE_OSEN:
+                return createOsenParams();
+            case WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2:
+                return SecurityParams.createPasspointParams(PASSPOINT_R2);
+            case WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3:
+                return SecurityParams.createPasspointParams(PASSPOINT_R3);
+            default:
+                throw new IllegalArgumentException("unknown security type " + securityType);
+        }
+    }
+
+    /**
+     * Create EAP security params.
+     */
+    private static @NonNull SecurityParams createWpaWpa2EnterpriseParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        params.mAllowedKeyManagement.set(KeyMgmt.IEEE8021X);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+        params.mAllowedProtocols.set(Protocol.WPA);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.TKIP);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.CCMP);
+        params.mAllowedGroupCiphers.set(GroupCipher.TKIP);
+        return params;
+    }
+
+    /**
+     * Create Passpoint security params.
+     */
+    private static @NonNull SecurityParams createPasspointParams(@PasspointRelease int release) {
+        SecurityParams params = new SecurityParams();
+        switch (release) {
+            case PASSPOINT_R1:
+            case PASSPOINT_R2:
+                params.mSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
+                break;
+            case PASSPOINT_R3:
+                params.mSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3;
+                params.mRequirePmf = true;
+                break;
+            default:
+                throw new IllegalArgumentException("invalid passpoint release " + release);
+        }
+
+        params.mAllowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        params.mAllowedKeyManagement.set(KeyMgmt.IEEE8021X);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.CCMP);
+
+        return params;
+    }
+
+    /**
+     * Create Enhanced Open params.
+     */
+    private static @NonNull SecurityParams createEnhancedOpenParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OWE;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.OWE);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.GCMP_128);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.GCMP_256);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.CCMP);
+        params.mAllowedGroupCiphers.set(GroupCipher.GCMP_128);
+        params.mAllowedGroupCiphers.set(GroupCipher.GCMP_256);
+
+        params.mRequirePmf = true;
+        return params;
+    }
+
+    /**
+     * Create Open params.
+     */
+    private static @NonNull SecurityParams createOpenParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OPEN;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.NONE);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+        params.mAllowedProtocols.set(Protocol.WPA);
+        return params;
+    }
+
+    /**
+     * Create OSEN params.
+     */
+    private static @NonNull SecurityParams createOsenParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OSEN;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.OSEN);
+
+        params.mAllowedProtocols.set(Protocol.OSEN);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.TKIP);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.CCMP);
+        params.mAllowedGroupCiphers.set(GroupCipher.TKIP);
+        return params;
+    }
+
+    /**
+     * Create WAPI-CERT params.
+     */
+    private static @NonNull SecurityParams createWapiCertParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.WAPI_CERT);
+
+        params.mAllowedProtocols.set(Protocol.WAPI);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.SMS4);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.SMS4);
+        return params;
+    }
+
+    /**
+     * Create WAPI-PSK params.
+     */
+    private static @NonNull SecurityParams createWapiPskParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.WAPI_PSK);
+
+        params.mAllowedProtocols.set(Protocol.WAPI);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.SMS4);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.SMS4);
+        return params;
+    }
+
+    /**
+     * Create WEP params.
+     */
+    private static @NonNull SecurityParams createWepParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WEP;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.NONE);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+
+        params.mAllowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+        params.mAllowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.TKIP);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.CCMP);
+        params.mAllowedGroupCiphers.set(GroupCipher.TKIP);
+        params.mAllowedGroupCiphers.set(GroupCipher.WEP40);
+        params.mAllowedGroupCiphers.set(GroupCipher.WEP104);
+        return params;
+    }
+
+    /**
+     * Create WPA3 Enterprise 192-bit params.
+     */
+    private static @NonNull SecurityParams createWpa3Enterprise192BitParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        params.mAllowedKeyManagement.set(KeyMgmt.IEEE8021X);
+        params.mAllowedKeyManagement.set(KeyMgmt.SUITE_B_192);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.GCMP_128);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.GCMP_256);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.GCMP_128);
+        params.mAllowedGroupCiphers.set(GroupCipher.GCMP_256);
+
+        params.mAllowedGroupManagementCiphers.set(GroupMgmtCipher.BIP_GMAC_256);
+
+        // Note: allowedSuiteBCiphers bitset will be set by the service once the
+        // certificates are attached to this profile
+
+        params.mRequirePmf = true;
+        return params;
+    }
+
+    /**
+     * Create WPA3 Enterprise params.
+     */
+    private static @NonNull SecurityParams createWpa3EnterpriseParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        params.mAllowedKeyManagement.set(KeyMgmt.IEEE8021X);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.GCMP_256);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.CCMP);
+        params.mAllowedGroupCiphers.set(GroupCipher.GCMP_256);
+
+        params.mRequirePmf = true;
+        return params;
+    }
+
+    /**
+     * Create WPA3 Personal params.
+     */
+    private static @NonNull SecurityParams createWpa3PersonalParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_SAE;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.SAE);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.GCMP_128);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.GCMP_256);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.CCMP);
+        params.mAllowedGroupCiphers.set(GroupCipher.GCMP_128);
+        params.mAllowedGroupCiphers.set(GroupCipher.GCMP_256);
+
+        params.mRequirePmf = true;
+        return params;
+    }
+
+    /**
+     * Create WPA/WPA2 Personal params.
+     */
+    private static @NonNull SecurityParams createWpaWpa2PersonalParams() {
+        SecurityParams params = new SecurityParams();
+        params.mSecurityType = WifiConfiguration.SECURITY_TYPE_PSK;
+
+        params.mAllowedKeyManagement.set(KeyMgmt.WPA_PSK);
+
+        params.mAllowedProtocols.set(Protocol.RSN);
+        params.mAllowedProtocols.set(Protocol.WPA);
+
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+        params.mAllowedPairwiseCiphers.set(PairwiseCipher.TKIP);
+
+        params.mAllowedGroupCiphers.set(GroupCipher.CCMP);
+        params.mAllowedGroupCiphers.set(GroupCipher.TKIP);
+        params.mAllowedGroupCiphers.set(GroupCipher.WEP40);
+        params.mAllowedGroupCiphers.set(GroupCipher.WEP104);
+        return params;
+    }
+}
diff --git a/framework/java/android/net/wifi/SoftApCapability.java b/framework/java/android/net/wifi/SoftApCapability.java
index dcb57ec..6f72f0b 100644
--- a/framework/java/android/net/wifi/SoftApCapability.java
+++ b/framework/java/android/net/wifi/SoftApCapability.java
@@ -20,11 +20,15 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.net.wifi.SoftApConfiguration.BandType;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -36,11 +40,13 @@
 @SystemApi
 public final class SoftApCapability implements Parcelable {
 
+    private static final String TAG = "SoftApCapability";
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
     /**
      * Support for automatic channel selection in driver (ACS).
      * Driver will auto select best channel based on interference to optimize performance.
      *
-     * flag when {@link R.bool.config_wifi_softap_acs_supported)} is true.
+     * flag when {@link R.bool.config_wifi_softap_acs_supported} is true.
      *
      * <p>
      * Use {@link WifiManager.SoftApCallback#onInfoChanged(SoftApInfo)} and
@@ -51,7 +57,7 @@
 
     /**
      * Support for client force disconnect.
-     * flag when {@link R.bool.config_wifi_sofap_client_force_disconnect_supported)} is true
+     * flag when {@link R.bool.config_wifiSofapClientForceDisconnectSupported} is true
      *
      * <p>
      * Several Soft AP client control features, e.g. specifying the maximum number of
@@ -61,20 +67,32 @@
      */
     public static final long SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 1 << 1;
 
-
     /**
      * Support for WPA3 Simultaneous Authentication of Equals (WPA3-SAE).
      *
-     * flag when {@link config_wifi_softap_sae_supported)} is true.
+     * flag when {@link config_wifi_softap_sae_supported} is true.
      */
     public static final long SOFTAP_FEATURE_WPA3_SAE = 1 << 2;
 
+    /**
+     * Support for MAC address customization.
+     * flag when {@link R.bool.config_wifiSoftapMacAddressCustomizationSupported} is true
+     *
+     * <p>
+     * Check feature support before invoking
+     * {@link SoftApConfiguration.Builder#setBssid(MadAddress)} or
+     * {@link SoftApConfiguration.Builder#setMacRandomizationSetting(int)} with
+     * {@link SoftApConfiguration.RANDOMIZATION_PERSISTENT}
+     */
+    public static final long SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION = 1 << 3;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @LongDef(flag = true, prefix = { "SOFTAP_FEATURE_" }, value = {
             SOFTAP_FEATURE_ACS_OFFLOAD,
             SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT,
             SOFTAP_FEATURE_WPA3_SAE,
+            SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION,
     })
     public @interface HotspotFeatures {}
 
@@ -83,6 +101,26 @@
     private int mMaximumSupportedClientNumber;
 
     /**
+     * A list storing supported 2.4G channels.
+     */
+    private int[] mSupportedChannelListIn24g = EMPTY_INT_ARRAY;
+
+    /**
+     * A list storing supported 5G channels.
+     */
+    private int[] mSupportedChannelListIn5g = EMPTY_INT_ARRAY;
+
+    /**
+     * A list storing supported 6G channels.
+     */
+    private int[] mSupportedChannelListIn6g = EMPTY_INT_ARRAY;
+
+    /**
+     * A list storing supported 60G channels.
+     */
+    private int[] mSupportedChannelListIn60g = EMPTY_INT_ARRAY;
+
+    /**
      * Get the maximum supported client numbers which AP resides on.
      */
     public int getMaxSupportedClients() {
@@ -111,12 +149,82 @@
     }
 
     /**
+     * Set supported channel list in target band type.
+     *
+     * @param band One of the following band types:
+     * {@link SoftApConfiguation#BAND_2GHZ}, {@link SoftApConfiguation#BAND_5GHZ},
+     * {@link SoftApConfiguation#BAND_6GHZ}, or {@link SoftApConfiguation#BAND_60GHZ}.
+     * @param  supportedChannelList supported channel list in target band
+     * @return true if band and supportedChannelList are valid, otherwise false.
+     *
+     * @throws IllegalArgumentException when band type is invalid.
+     * @hide
+     */
+    public boolean setSupportedChannelList(@BandType int band,
+            @Nullable int[] supportedChannelList) {
+        if (supportedChannelList == null)  return false;
+        switch (band) {
+            case SoftApConfiguration.BAND_2GHZ:
+                mSupportedChannelListIn24g = supportedChannelList;
+                break;
+            case SoftApConfiguration.BAND_5GHZ:
+                mSupportedChannelListIn5g = supportedChannelList;
+                break;
+            case SoftApConfiguration.BAND_6GHZ:
+                mSupportedChannelListIn6g = supportedChannelList;
+                break;
+            case SoftApConfiguration.BAND_60GHZ:
+                mSupportedChannelListIn60g = supportedChannelList;
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid band: " + band);
+        }
+        return true;
+    }
+
+    /**
+     * Returns a list of the supported channels in the given band.
+     * The result depends on the on the country code that has been set.
+     * Can be used to set the channel of the AP with the
+     * {@link SoftapConfiguration.Builder#setChannel(int, int)} API.
+     *
+     * @param band One of the following band types:
+     * {@link SoftApConfiguation#BAND_2GHZ}, {@link SoftApConfiguation#BAND_5GHZ},
+     * {@link SoftApConfiguation#BAND_6GHZ}, {@link SoftApConfiguation#BAND_60GHZ}.
+     * @return List of supported channels for the band.
+     *
+     * @throws IllegalArgumentException when band type is invalid.
+     */
+    @NonNull
+    public int[] getSupportedChannelList(@BandType int band) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        switch (band) {
+            case SoftApConfiguration.BAND_2GHZ:
+                return mSupportedChannelListIn24g;
+            case SoftApConfiguration.BAND_5GHZ:
+                return mSupportedChannelListIn5g;
+            case SoftApConfiguration.BAND_6GHZ:
+                return mSupportedChannelListIn6g;
+            case SoftApConfiguration.BAND_60GHZ:
+                return mSupportedChannelListIn60g;
+            default:
+                throw new IllegalArgumentException("Invalid band: " + band);
+        }
+    }
+
+    /**
      * @hide
      */
     public SoftApCapability(@Nullable SoftApCapability source) {
         if (source != null) {
             mSupportedFeatures = source.mSupportedFeatures;
             mMaximumSupportedClientNumber = source.mMaximumSupportedClientNumber;
+            mSupportedChannelListIn24g = source.mSupportedChannelListIn24g;
+            mSupportedChannelListIn5g = source.mSupportedChannelListIn5g;
+            mSupportedChannelListIn6g = source.mSupportedChannelListIn6g;
+            mSupportedChannelListIn60g = source.mSupportedChannelListIn60g;
         }
     }
 
@@ -144,15 +252,22 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeLong(mSupportedFeatures);
         dest.writeInt(mMaximumSupportedClientNumber);
+        dest.writeIntArray(mSupportedChannelListIn24g);
+        dest.writeIntArray(mSupportedChannelListIn5g);
+        dest.writeIntArray(mSupportedChannelListIn6g);
+        dest.writeIntArray(mSupportedChannelListIn60g);
     }
 
     @NonNull
     /** Implement the Parcelable interface */
     public static final Creator<SoftApCapability> CREATOR = new Creator<SoftApCapability>() {
         public SoftApCapability createFromParcel(Parcel in) {
-            long supportedFeatures = in.readLong();
-            SoftApCapability capability = new SoftApCapability(supportedFeatures);
+            SoftApCapability capability = new SoftApCapability(in.readLong());
             capability.mMaximumSupportedClientNumber = in.readInt();
+            capability.setSupportedChannelList(SoftApConfiguration.BAND_2GHZ, in.createIntArray());
+            capability.setSupportedChannelList(SoftApConfiguration.BAND_5GHZ, in.createIntArray());
+            capability.setSupportedChannelList(SoftApConfiguration.BAND_6GHZ, in.createIntArray());
+            capability.setSupportedChannelList(SoftApConfiguration.BAND_60GHZ, in.createIntArray());
             return capability;
         }
 
@@ -167,6 +282,12 @@
         StringBuilder sbuf = new StringBuilder();
         sbuf.append("SupportedFeatures=").append(mSupportedFeatures);
         sbuf.append("MaximumSupportedClientNumber=").append(mMaximumSupportedClientNumber);
+        sbuf.append("SupportedChannelListIn24g")
+                .append(Arrays.toString(mSupportedChannelListIn24g));
+        sbuf.append("SupportedChannelListIn5g").append(Arrays.toString(mSupportedChannelListIn5g));
+        sbuf.append("SupportedChannelListIn6g").append(Arrays.toString(mSupportedChannelListIn6g));
+        sbuf.append("SupportedChannelListIn60g")
+                .append(Arrays.toString(mSupportedChannelListIn60g));
         return sbuf.toString();
     }
 
@@ -176,11 +297,19 @@
         if (!(o instanceof SoftApCapability)) return false;
         SoftApCapability capability = (SoftApCapability) o;
         return mSupportedFeatures == capability.mSupportedFeatures
-                && mMaximumSupportedClientNumber == capability.mMaximumSupportedClientNumber;
+                && mMaximumSupportedClientNumber == capability.mMaximumSupportedClientNumber
+                && Arrays.equals(mSupportedChannelListIn24g, capability.mSupportedChannelListIn24g)
+                && Arrays.equals(mSupportedChannelListIn5g, capability.mSupportedChannelListIn5g)
+                && Arrays.equals(mSupportedChannelListIn6g, capability.mSupportedChannelListIn6g)
+                && Arrays.equals(mSupportedChannelListIn60g, capability.mSupportedChannelListIn60g);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSupportedFeatures, mMaximumSupportedClientNumber);
+        return Objects.hash(mSupportedFeatures, mMaximumSupportedClientNumber,
+                Arrays.hashCode(mSupportedChannelListIn24g),
+                Arrays.hashCode(mSupportedChannelListIn5g),
+                Arrays.hashCode(mSupportedChannelListIn6g),
+                Arrays.hashCode(mSupportedChannelListIn60g));
     }
 }
diff --git a/framework/java/android/net/wifi/SoftApConfiguration.java b/framework/java/android/net/wifi/SoftApConfiguration.java
index d2ff658..d36acb7 100644
--- a/framework/java/android/net/wifi/SoftApConfiguration.java
+++ b/framework/java/android/net/wifi/SoftApConfiguration.java
@@ -26,13 +26,14 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseIntArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.modules.utils.build.SdkLevel;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.nio.charset.CharsetEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
@@ -87,9 +88,19 @@
     public static final int BAND_6GHZ = 1 << 2;
 
     /**
+     * 60GHz band.
+     * @hide
+     */
+    @SystemApi
+    public static final int BAND_60GHZ = 1 << 3;
+
+    /**
      * Device is allowed to choose the optimal band (2Ghz, 5Ghz, 6Ghz) based on device capability,
      * operating country code and current radio conditions.
      * @hide
+     *
+     * @deprecated The bands are a bit mask - use any combination of {@code BAND_},
+     * for instance {@code BAND_2GHZ | BAND_5GHZ | BAND_6GHZ}.
      */
     @SystemApi
     public static final int BAND_ANY = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ;
@@ -100,11 +111,13 @@
             BAND_2GHZ,
             BAND_5GHZ,
             BAND_6GHZ,
+            BAND_60GHZ,
     })
     public @interface BandType {}
 
     private static boolean isBandValid(@BandType int band) {
-        return ((band != 0) && ((band & ~BAND_ANY) == 0));
+        int bandAny = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ | BAND_60GHZ;
+        return ((band != 0) && ((band & ~bandAny) == 0));
     }
 
     private static final int MIN_CH_2G_BAND = 1;
@@ -113,6 +126,8 @@
     private static final int MAX_CH_5G_BAND = 196;
     private static final int MIN_CH_6G_BAND = 1;
     private static final int MAX_CH_6G_BAND = 253;
+    private static final int MIN_CH_60G_BAND = 1;
+    private static final int MAX_CH_60G_BAND = 6;
 
 
 
@@ -135,6 +150,13 @@
                     return false;
                 }
                 break;
+
+            case BAND_60GHZ:
+                if (channel < MIN_CH_60G_BAND || channel >  MAX_CH_60G_BAND) {
+                    return false;
+                }
+                break;
+
             default:
                 return false;
         }
@@ -164,16 +186,12 @@
     private final boolean mHiddenSsid;
 
     /**
-     * The operating band of the AP.
-     * One or combination of the following band type:
-     * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
+     * The operating channels of the dual APs.
+     *
+     * The SparseIntArray that consists the band and the channel of matching the band.
      */
-    private final @BandType int mBand;
-
-    /**
-     * The operating channel of the AP.
-     */
-    private final int mChannel;
+    @NonNull
+    private final SparseIntArray mChannels;
 
     /**
      * The maximim allowed number of clients that can associate to the AP.
@@ -217,6 +235,34 @@
      */
     private final long mShutdownTimeoutMillis;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"RANDOMIZATION_"}, value = {
+            RANDOMIZATION_NONE,
+            RANDOMIZATION_PERSISTENT})
+    public @interface MacRandomizationSetting {}
+
+    /**
+     * Use factory MAC as BSSID for the AP
+     * @hide
+     */
+    @SystemApi
+    public static final int RANDOMIZATION_NONE = 0;
+    /**
+     * Generate a randomized MAC as BSSID for the AP
+     * @hide
+     */
+    @SystemApi
+    public static final int RANDOMIZATION_PERSISTENT = 1;
+
+    /**
+     * Level of MAC randomization for the AP BSSID.
+     * @hide
+     */
+    @MacRandomizationSetting
+    private int mMacRandomizationSetting;
+
+
     /**
      * THe definition of security type OPEN.
      */
@@ -249,16 +295,21 @@
 
     /** Private constructor for Builder and Parcelable implementation. */
     private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
-            @Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel,
+            @Nullable String passphrase, boolean hiddenSsid, @NonNull SparseIntArray channels,
             @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled,
             long shutdownTimeoutMillis, boolean clientControlByUser,
-            @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList) {
+            @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList,
+            int macRandomizationSetting) {
         mSsid = ssid;
         mBssid = bssid;
         mPassphrase = passphrase;
         mHiddenSsid = hiddenSsid;
-        mBand = band;
-        mChannel = channel;
+        if (channels.size() != 0) {
+            mChannels = channels.clone();
+        } else {
+            mChannels = new SparseIntArray(1);
+            mChannels.put(BAND_2GHZ, 0);
+        }
         mSecurityType = securityType;
         mMaxNumberOfClients = maxNumberOfClients;
         mAutoShutdownEnabled = shutdownTimeoutEnabled;
@@ -266,6 +317,7 @@
         mClientControlByUser = clientControlByUser;
         mBlockedClientList = new ArrayList<>(blockedList);
         mAllowedClientList = new ArrayList<>(allowedList);
+        mMacRandomizationSetting = macRandomizationSetting;
     }
 
     @Override
@@ -281,42 +333,42 @@
                 && Objects.equals(mBssid, other.mBssid)
                 && Objects.equals(mPassphrase, other.mPassphrase)
                 && mHiddenSsid == other.mHiddenSsid
-                && mBand == other.mBand
-                && mChannel == other.mChannel
+                && mChannels.toString().equals(other.mChannels.toString())
                 && mSecurityType == other.mSecurityType
                 && mMaxNumberOfClients == other.mMaxNumberOfClients
                 && mAutoShutdownEnabled == other.mAutoShutdownEnabled
                 && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis
                 && mClientControlByUser == other.mClientControlByUser
                 && Objects.equals(mBlockedClientList, other.mBlockedClientList)
-                && Objects.equals(mAllowedClientList, other.mAllowedClientList);
+                && Objects.equals(mAllowedClientList, other.mAllowedClientList)
+                && mMacRandomizationSetting == other.mMacRandomizationSetting;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid,
-                mBand, mChannel, mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled,
+                mChannels.toString(), mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled,
                 mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList,
-                mAllowedClientList);
+                mAllowedClientList, mMacRandomizationSetting);
     }
 
     @Override
     public String toString() {
         StringBuilder sbuf = new StringBuilder();
-        sbuf.append("ssid=").append(mSsid);
-        if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString());
-        sbuf.append(" \n Passphrase =").append(
+        sbuf.append("ssid = ").append(mSsid);
+        if (mBssid != null) sbuf.append(" \n bssid = ").append(mBssid.toString());
+        sbuf.append(" \n Passphrase = ").append(
                 TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>");
-        sbuf.append(" \n HiddenSsid =").append(mHiddenSsid);
-        sbuf.append(" \n Band =").append(mBand);
-        sbuf.append(" \n Channel =").append(mChannel);
-        sbuf.append(" \n SecurityType=").append(getSecurityType());
-        sbuf.append(" \n MaxClient=").append(mMaxNumberOfClients);
-        sbuf.append(" \n AutoShutdownEnabled=").append(mAutoShutdownEnabled);
-        sbuf.append(" \n ShutdownTimeoutMillis=").append(mShutdownTimeoutMillis);
-        sbuf.append(" \n ClientControlByUser=").append(mClientControlByUser);
-        sbuf.append(" \n BlockedClientList=").append(mBlockedClientList);
-        sbuf.append(" \n AllowedClientList=").append(mAllowedClientList);
+        sbuf.append(" \n HiddenSsid = ").append(mHiddenSsid);
+        sbuf.append(" \n Channels = ").append(mChannels);
+        sbuf.append(" \n SecurityType = ").append(getSecurityType());
+        sbuf.append(" \n MaxClient = ").append(mMaxNumberOfClients);
+        sbuf.append(" \n AutoShutdownEnabled = ").append(mAutoShutdownEnabled);
+        sbuf.append(" \n ShutdownTimeoutMillis = ").append(mShutdownTimeoutMillis);
+        sbuf.append(" \n ClientControlByUser = ").append(mClientControlByUser);
+        sbuf.append(" \n BlockedClientList = ").append(mBlockedClientList);
+        sbuf.append(" \n AllowedClientList= ").append(mAllowedClientList);
+        sbuf.append(" \n MacRandomizationSetting = ").append(mMacRandomizationSetting);
         return sbuf.toString();
     }
 
@@ -326,8 +378,7 @@
         dest.writeParcelable(mBssid, flags);
         dest.writeString(mPassphrase);
         dest.writeBoolean(mHiddenSsid);
-        dest.writeInt(mBand);
-        dest.writeInt(mChannel);
+        writeSparseIntArray(dest, mChannels);
         dest.writeInt(mSecurityType);
         dest.writeInt(mMaxNumberOfClients);
         dest.writeBoolean(mAutoShutdownEnabled);
@@ -335,8 +386,45 @@
         dest.writeBoolean(mClientControlByUser);
         dest.writeTypedList(mBlockedClientList);
         dest.writeTypedList(mAllowedClientList);
+        dest.writeInt(mMacRandomizationSetting);
     }
 
+    /* Reference from frameworks/base/core/java/android/os/Parcel.java */
+    private static void writeSparseIntArray(@NonNull Parcel dest,
+            @Nullable SparseIntArray val) {
+        if (val == null) {
+            dest.writeInt(-1);
+            return;
+        }
+        int n = val.size();
+        dest.writeInt(n);
+        int i = 0;
+        while (i < n) {
+            dest.writeInt(val.keyAt(i));
+            dest.writeInt(val.valueAt(i));
+            i++;
+        }
+    }
+
+
+    /* Reference from frameworks/base/core/java/android/os/Parcel.java */
+    @NonNull
+    private static SparseIntArray readSparseIntArray(@NonNull Parcel in) {
+        int n = in.readInt();
+        if (n < 0) {
+            return new SparseIntArray();
+        }
+        SparseIntArray sa = new SparseIntArray(n);
+        while (n > 0) {
+            int key = in.readInt();
+            int value = in.readInt();
+            sa.append(key, value);
+            n--;
+        }
+        return sa;
+    }
+
+
     @Override
     public int describeContents() {
         return 0;
@@ -349,10 +437,10 @@
             return new SoftApConfiguration(
                     in.readString(),
                     in.readParcelable(MacAddress.class.getClassLoader()),
-                    in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(),
+                    in.readString(), in.readBoolean(), readSparseIntArray(in), in.readInt(),
                     in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(),
                     in.createTypedArrayList(MacAddress.CREATOR),
-                    in.createTypedArrayList(MacAddress.CREATOR));
+                    in.createTypedArrayList(MacAddress.CREATOR), in.readInt());
         }
 
         @Override
@@ -363,7 +451,7 @@
 
     /**
      * Return String set to be the SSID for the AP.
-     * {@link Builder#setSsid(String)}.
+     * See also {@link Builder#setSsid(String)}.
      */
     @Nullable
     public String getSsid() {
@@ -372,7 +460,7 @@
 
     /**
      * Returns MAC address set to be BSSID for the AP.
-     * {@link Builder#setBssid(MacAddress)}.
+     * See also {@link Builder#setBssid(MacAddress)}.
      */
     @Nullable
     public MacAddress getBssid() {
@@ -381,7 +469,7 @@
 
     /**
      * Returns String set to be passphrase for current AP.
-     * {@link Builder#setPassphrase(String, int)}.
+     * See also {@link Builder#setPassphrase(String, int)}.
      */
     @Nullable
     public String getPassphrase() {
@@ -391,7 +479,7 @@
     /**
      * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or
      * not (false: broadcasts its SSID) for the AP.
-     * {@link Builder#setHiddenSsid(boolean)}.
+     * See also {@link Builder#setHiddenSsid(boolean)}.
      */
     public boolean isHiddenSsid() {
         return mHiddenSsid;
@@ -400,27 +488,75 @@
     /**
      * Returns band type set to be the band for the AP.
      *
-     * One or combination of the following band type:
-     * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
+     * One or combination of {@code BAND_}, for instance
+     * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}.
      *
-     * {@link Builder#setBand(int)}.
+     * Note: Returns the lowest band when more than one band is set.
+     * Use {@link #getBands()} to get dual bands setting.
+     *
+     * See also {@link Builder#setBand(int)}.
      *
      * @hide
      */
     @SystemApi
     public @BandType int getBand() {
-        return mBand;
+        return mChannels.keyAt(0);
+    }
+
+    /**
+     * Returns a sorted array in ascending order that consists of the configured band types
+     * for the APs.
+     *
+     * The band type is one or combination of {@code BAND_}, for instance
+     * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}.
+     *
+     * Note: return array may only include one band when current setting is single AP mode.
+     * See also {@link Builder#setBands(int[])}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public @NonNull int[] getBands() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        int[] bands = new int[mChannels.size()];
+        for (int i = 0; i < bands.length; i++) {
+            bands[i] = mChannels.keyAt(i);
+        }
+        return bands;
     }
 
     /**
      * Returns Integer set to be the channel for the AP.
-     * {@link Builder#setChannel(int)}.
+     *
+     * Note: Returns the channel which associated to the lowest band if more than one channel
+     * is set. Use {@link Builder#getChannels()} to get dual channel setting.
+     * See also {@link Builder#setChannel(int, int)}.
      *
      * @hide
      */
     @SystemApi
     public int getChannel() {
-        return mChannel;
+        return mChannels.valueAt(0);
+    }
+
+
+    /**
+     * Returns SparseIntArray (key: {@code BandType} , value: channel) that consists of
+     * the configured bands and channels for the AP(s).
+     *
+     * Note: return array may only include one channel when current setting is single AP mode.
+     * See also {@link Builder#setChannels(SparseIntArray)}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public @NonNull SparseIntArray getChannels() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mChannels.clone();
     }
 
     /**
@@ -438,7 +574,7 @@
 
     /**
      * Returns the maximum number of clients that can associate to the AP.
-     * {@link Builder#setMaxNumberOfClients(int)}.
+     * See also {@link Builder#setMaxNumberOfClients(int)}.
      *
      * @hide
      */
@@ -450,7 +586,7 @@
     /**
      * Returns whether auto shutdown is enabled or not.
      * The Soft AP will shutdown when there are no devices associated to it for
-     * the timeout duration. See {@link Builder#setAutoShutdownEnabled(boolean)}.
+     * the timeout duration. See also {@link Builder#setAutoShutdownEnabled(boolean)}.
      *
      * @hide
      */
@@ -462,7 +598,7 @@
     /**
      * Returns the shutdown timeout in milliseconds.
      * The Soft AP will shutdown when there are no devices associated to it for
-     * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(long)}.
+     * the timeout duration. See also {@link Builder#setShutdownTimeoutMillis(long)}.
      *
      * @hide
      */
@@ -474,7 +610,7 @@
     /**
      * Returns a flag indicating whether clients need to be pre-approved by the user.
      * (true: authorization required) or not (false: not required).
-     * {@link Builder#setClientControlByUserEnabled(Boolean)}.
+     * See also {@link Builder#setClientControlByUserEnabled(Boolean)}.
      *
      * @hide
      */
@@ -509,6 +645,21 @@
     }
 
     /**
+     * Returns the level of MAC randomization for the AP BSSID.
+     * See also {@link Builder#setMacRandomizationSetting(int)}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @MacRandomizationSetting
+    public int getMacRandomizationSetting() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mMacRandomizationSetting;
+    }
+
+    /**
      * Returns a {@link WifiConfiguration} representation of this {@link SoftApConfiguration}.
      * Note that SoftApConfiguration may contain configuration which is cannot be represented
      * by the legacy WifiConfiguration, in such cases a null will be returned.
@@ -527,7 +678,7 @@
         wifiConfig.SSID = mSsid;
         wifiConfig.preSharedKey = mPassphrase;
         wifiConfig.hiddenSSID = mHiddenSsid;
-        wifiConfig.apChannel = mChannel;
+        wifiConfig.apChannel = getChannel();
         switch (mSecurityType) {
             case SECURITY_TYPE_OPEN:
                 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
@@ -541,7 +692,7 @@
                 return null;
         }
 
-        switch (mBand) {
+        switch (getBand()) {
             case BAND_2GHZ:
                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_2GHZ;
                 break;
@@ -555,7 +706,7 @@
                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_ANY;
                 break;
             default:
-                Log.e(TAG, "Convert fail, unsupported band setting :" + mBand);
+                Log.e(TAG, "Convert fail, unsupported band setting :" + getBand());
                 return null;
         }
         return wifiConfig;
@@ -576,8 +727,7 @@
         private MacAddress mBssid;
         private String mPassphrase;
         private boolean mHiddenSsid;
-        private int mBand;
-        private int mChannel;
+        private SparseIntArray mChannels;
         private int mMaxNumberOfClients;
         private int mSecurityType;
         private boolean mAutoShutdownEnabled;
@@ -585,6 +735,7 @@
         private boolean mClientControlByUser;
         private List<MacAddress> mBlockedClientList;
         private List<MacAddress> mAllowedClientList;
+        private int mMacRandomizationSetting;
 
         /**
          * Constructs a Builder with default values (see {@link Builder}).
@@ -594,8 +745,8 @@
             mBssid = null;
             mPassphrase = null;
             mHiddenSsid = false;
-            mBand = BAND_2GHZ;
-            mChannel = 0;
+            mChannels = new SparseIntArray(1);
+            mChannels.put(BAND_2GHZ, 0);
             mMaxNumberOfClients = 0;
             mSecurityType = SECURITY_TYPE_OPEN;
             mAutoShutdownEnabled = true; // enabled by default.
@@ -603,6 +754,7 @@
             mClientControlByUser = false;
             mBlockedClientList = new ArrayList<>();
             mAllowedClientList = new ArrayList<>();
+            mMacRandomizationSetting = RANDOMIZATION_PERSISTENT;
         }
 
         /**
@@ -615,8 +767,7 @@
             mBssid = other.mBssid;
             mPassphrase = other.mPassphrase;
             mHiddenSsid = other.mHiddenSsid;
-            mBand = other.mBand;
-            mChannel = other.mChannel;
+            mChannels = other.mChannels.clone();
             mMaxNumberOfClients = other.mMaxNumberOfClients;
             mSecurityType = other.mSecurityType;
             mAutoShutdownEnabled = other.mAutoShutdownEnabled;
@@ -624,6 +775,7 @@
             mClientControlByUser = other.mClientControlByUser;
             mBlockedClientList = new ArrayList<>(other.mBlockedClientList);
             mAllowedClientList = new ArrayList<>(other.mAllowedClientList);
+            mMacRandomizationSetting = other.mMacRandomizationSetting;
         }
 
         /**
@@ -639,9 +791,9 @@
                 }
             }
             return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
-                    mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients,
+                    mHiddenSsid, mChannels, mSecurityType, mMaxNumberOfClients,
                     mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser,
-                    mBlockedClientList, mAllowedClientList);
+                    mBlockedClientList, mAllowedClientList, mMacRandomizationSetting);
         }
 
         /**
@@ -670,17 +822,41 @@
          * Specifies a BSSID for the AP.
          * <p>
          * <li>If not set, defaults to null.</li>
+         *
+         * If multiple bands are requested via {@link #setBands(int[])} or
+         * {@link #setChannels(SparseIntArray)}, HAL will derive 2 MAC addresses since framework
+         * only sends down 1 MAC address.
+         *
+         * An example (but different implementation may perform a different mapping):
+         * <li>MAC address 1: copy value of MAC address,
+         * and set byte 1 = (0xFF - BSSID[1])</li>
+         * <li>MAC address 2: copy value of MAC address,
+         * and set byte 2 = (0xFF - BSSID[2])</li>
+         *
+         * Example BSSID argument: e2:38:60:c4:0e:b7
+         * Derived MAC address 1: e2:c7:60:c4:0e:b7
+         * Derived MAC address 2: e2:38:9f:c4:0e:b7
+         *
+         * <p>
+         * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
+         * {@link SoftApCapability#areFeaturesSupported(long)}
+         * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine
+         * whether or not this feature is supported.
+         *
          * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
          *              responsible for avoiding collisions.
          * @return Builder for chaining.
-         * @throws IllegalArgumentException when the given BSSID is the all-zero or broadcast MAC
-         *                                  address.
+         * @throws IllegalArgumentException when the given BSSID is the all-zero
+         *                                  , multicast or broadcast MAC address.
          */
         @NonNull
         public Builder setBssid(@Nullable MacAddress bssid) {
             if (bssid != null) {
                 Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS));
-                Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS));
+                if (bssid.getAddressType() != MacAddress.TYPE_UNICAST) {
+                    throw new IllegalArgumentException("bssid doesn't support "
+                            + "multicast or broadcast mac address");
+                }
             }
             mBssid = bssid;
             return this;
@@ -712,10 +888,6 @@
                 }
             } else {
                 Preconditions.checkStringNotEmpty(passphrase);
-                final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
-                if (!asciiEncoder.canEncode(passphrase)) {
-                    throw new IllegalArgumentException("passphrase not ASCII encodable");
-                }
                 if (securityType == SECURITY_TYPE_WPA2_PSK
                         || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) {
                     if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) {
@@ -754,53 +926,155 @@
          * @param band One or combination of the following band type:
          * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
          * @return Builder for chaining.
+         * @throws IllegalArgumentException when an invalid band type is provided.
          */
         @NonNull
         public Builder setBand(@BandType int band) {
             if (!isBandValid(band)) {
-                throw new IllegalArgumentException("Invalid band type");
+                throw new IllegalArgumentException("Invalid band type: " + band);
             }
-            mBand = band;
-            // Since band preference is specified, no specific channel is selected.
-            mChannel = 0;
+            mChannels = new SparseIntArray(1);
+            mChannels.put(band, 0);
             return this;
         }
 
         /**
+         * Specifies the bands for the APs.
+         * If more than 1 band is set, this will bring up concurrent APs.
+         * on the requested bands (if possible).
+         * <p>
+         *
+         * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
+         * whether or not concurrent APs are supported.
+         *
+         * @param bands Array of the {@link #BandType}.
+         * @return Builder for chaining.
+         * @throws IllegalArgumentException when more than 2 bands are set or an invalid band type
+         *                                  is provided.
+         */
+        @NonNull
+        public Builder setBands(@NonNull int[] bands) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            if (bands.length == 0 || bands.length > 2) {
+                throw new IllegalArgumentException("Unsupported number of bands("
+                        + bands.length + ") configured");
+            }
+            SparseIntArray channels = new SparseIntArray(bands.length);
+            for (int val : bands) {
+                if (!isBandValid(val)) {
+                    throw new IllegalArgumentException("Invalid band type: " + val);
+                }
+                channels.put(val, 0);
+            }
+            mChannels = channels;
+            return this;
+        }
+
+
+        /**
          * Specifies the channel and associated band for the AP.
          *
          * The channel which AP resides on. Valid channels are country dependent.
+         * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
+         * valid channels.
+         *
          * <p>
-         * The default for the channel is a the special value 0 to have the framework
-         * auto-select a valid channel from the band configured with
+         * If not set, the default for the channel is the special value 0 which has the
+         * framework auto-select a valid channel from the band configured with
          * {@link #setBand(int)}.
          *
-         * The channel auto selection will offload to driver when
-         * {@link SoftApCapability#areFeaturesSupported(
-         * SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD)}
-         * return true. Driver will auto select best channel which based on environment
-         * interference to get best performance. Check {@link SoftApCapability} to get more detail.
+         * The channel auto selection will be offloaded to driver when
+         * {@link SoftApCapability#areFeaturesSupported(long)}
+         * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
+         * return true. The driver will auto select the best channel (e.g. best performance)
+         * based on environment interference. Check {@link SoftApCapability} for more detail.
          *
-         * Note, since 6GHz band use the same channel numbering of 2.4GHz and 5GHZ bands,
-         * the caller needs to pass the band containing the selected channel.
+         * The API contains (band, channel) input since the 6GHz band uses the same channel
+         * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to
+         * uniquely identify individual channels.
          *
          * <p>
-         * <li>If not set, defaults to 0.</li>
          * @param channel operating channel of the AP.
          * @param band containing this channel.
          * @return Builder for chaining.
+         * @throws IllegalArgumentException when the invalid channel or band type is configured.
          */
         @NonNull
         public Builder setChannel(int channel, @BandType int band) {
             if (!isChannelBandPairValid(channel, band)) {
-                throw new IllegalArgumentException("Invalid band type");
+                throw new IllegalArgumentException("Invalid channel(" + channel
+                        + ") & band (" + band + ") configured");
             }
-            mBand = band;
-            mChannel = channel;
+            mChannels = new SparseIntArray(1);
+            mChannels.put(band, channel);
             return this;
         }
 
         /**
+         * Specifies the channels and associated bands for the APs.
+         *
+         * When more than 1 channel is set, this will bring up concurrent APs on the requested
+         * channels and bands (if possible).
+         *
+         * Valid channels are country dependent.
+         * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
+         * valid channels in each band.
+         *
+         * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
+         * whether or not concurrent APs are supported.
+         *
+         * <p>
+         * If not set, the default for the channel is the special value 0 which has the framework
+         * auto-select a valid channel from the band configured with {@link #setBands(int[])}.
+         *
+         * The channel auto selection will be offloaded to driver when
+         * {@link SoftApCapability#areFeaturesSupported(long)}
+         * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
+         * returns true. The driver will auto select the best channel (e.g. best performance)
+         * based on environment interference. Check {@link SoftApCapability} for more detail.
+         *
+         * The API contains (band, channel) input since the 6GHz band uses the same channel
+         * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to
+         * uniquely identify individual channels.
+         *
+         * <p>
+         * @param channels SparseIntArray (key: {@code #BandType} , value: channel) consists of
+         *                 {@code BAND_} and corresponding channel.
+         * @return Builder for chaining.
+         * @throws IllegalArgumentException when more than 2 channels are set or the invalid
+         *                                  channel or band type is configured.
+         */
+        @NonNull
+        public Builder setChannels(@NonNull SparseIntArray channels) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            if (channels.size() == 0 || channels.size() > 2) {
+                throw new IllegalArgumentException("Unsupported number of channels("
+                        + channels.size() + ") configured");
+            }
+            for (int i = 0; i < channels.size(); i++) {
+                int channel = channels.valueAt(i);
+                int band = channels.keyAt(i);
+                if (channel == 0) {
+                    if (!isBandValid(band)) {
+                        throw new IllegalArgumentException("Invalid band type: " + band);
+                    }
+                } else {
+                    if (!isChannelBandPairValid(channel, band)) {
+                        throw new IllegalArgumentException("Invalid channel(" + channel
+                                + ") & band (" + band + ") configured");
+                    }
+                }
+            }
+            mChannels = channels.clone();
+            return this;
+        }
+
+
+        /**
          * Specifies the maximum number of clients that can associate to the AP.
          *
          * The maximum number of clients (STAs) which can associate to the AP.
@@ -815,14 +1089,14 @@
          * <p>
          * <li>If not set, defaults to 0.</li>
          *
-         * This method requires hardware support. If the method is used to set a
+         * This method requires HAL support. If the method is used to set a
          * non-zero {@code maxNumberOfClients} value then
          * {@link WifiManager#startTetheredHotspot} will report error code
          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
          *
          * <p>
          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
-         * {@link SoftApCapability#areFeaturesSupported(int)}
+         * {@link SoftApCapability#areFeaturesSupported(long)}
          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether
          * or not this feature is supported.
          *
@@ -896,13 +1170,13 @@
          * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}.
          *
          * <p>
-         * This method requires hardware support. Hardware support can be determined using
+         * This method requires HAL support. HAL support can be determined using
          * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
-         * {@link SoftApCapability#areFeaturesSupported(int)}
+         * {@link SoftApCapability#areFeaturesSupported(long)}
          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
          *
          * <p>
-         * If the method is called on a device without hardware support then starting the soft AP
+         * If the method is called on a device without HAL support then starting the soft AP
          * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
          *
@@ -951,13 +1225,13 @@
          * to the Soft AP.
          *
          * <p>
-         * This method requires hardware support. Hardware support can be determined using
+         * This method requires HAL support. HAL support can be determined using
          * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
-         * {@link SoftApCapability#areFeaturesSupported(int)}
+         * {@link SoftApCapability#areFeaturesSupported(long)}
          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
          *
          * <p>
-         * If the method is called on a device without hardware support then starting the soft AP
+         * If the method is called on a device without HAL support then starting the soft AP
          * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
          *
@@ -969,5 +1243,37 @@
             mBlockedClientList = new ArrayList<>(blockedClientList);
             return this;
         }
+
+        /**
+         * Specifies the level of MAC randomization for the AP BSSID.
+         * The Soft AP BSSID will be randomized only if the BSSID isn't set
+         * {@link #setBssid(MacAddress)} and this method is either uncalled
+         * or called with {@link #RANDOMIZATION_PERSISTENT}.
+         *
+         * <p>
+         * <li>If not set, defaults to {@link #RANDOMIZATION_PERSISTENT}</li>
+         *
+         * <p>
+         * Requires HAL support when set to {@link #RANDOMIZATION_PERSISTENT}.
+         * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
+         * {@link SoftApCapability#areFeaturesSupported(long)}
+         * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine
+         * whether or not this feature is supported.
+         *
+         * @param macRandomizationSetting One of the following setting:
+         * {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}.
+         * @return Builder for chaining.
+         *
+         * @see #setBssid(MacAddress)
+         */
+        @NonNull
+        public Builder setMacRandomizationSetting(
+                @MacRandomizationSetting int macRandomizationSetting) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            mMacRandomizationSetting = macRandomizationSetting;
+            return this;
+        }
     }
 }
diff --git a/framework/java/android/net/wifi/SoftApInfo.java b/framework/java/android/net/wifi/SoftApInfo.java
index 24ed8ef..e42e786 100644
--- a/framework/java/android/net/wifi/SoftApInfo.java
+++ b/framework/java/android/net/wifi/SoftApInfo.java
@@ -19,9 +19,13 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.net.MacAddress;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.util.Preconditions;
+import com.android.modules.utils.build.SdkLevel;
+
 import java.util.Objects;
 
 /**
@@ -82,7 +86,33 @@
      */
     public static final int CHANNEL_WIDTH_160MHZ = 6;
 
+    /**
+     * AP Channel bandwidth is 2160 MHZ.
+     *
+     * @see #getBandwidth()
+     */
+    public static final int CHANNEL_WIDTH_2160MHZ = 7;
 
+    /**
+     * AP Channel bandwidth is 4320 MHZ.
+     *
+     * @see #getBandwidth()
+     */
+    public static final int CHANNEL_WIDTH_4320MHZ = 8;
+
+    /**
+     * AP Channel bandwidth is 6480 MHZ.
+     *
+     * @see #getBandwidth()
+     */
+    public static final int CHANNEL_WIDTH_6480MHZ = 9;
+
+    /**
+     * AP Channel bandwidth is 8640 MHZ.
+     *
+     * @see #getBandwidth()
+     */
+    public static final int CHANNEL_WIDTH_8640MHZ = 10;
 
     /** The frequency which AP resides on.  */
     private int mFrequency = 0;
@@ -90,6 +120,19 @@
     @WifiAnnotations.Bandwidth
     private int mBandwidth = CHANNEL_WIDTH_INVALID;
 
+    /** The MAC Address which AP resides on. */
+    @Nullable
+    private MacAddress mBssid;
+
+    /** The identifier of the AP instance which AP resides on with current info. */
+    @Nullable
+    private String mApInstanceIdentifier;
+
+    /**
+     * The operational mode of the AP.
+     */
+    private @WifiAnnotations.WifiStandard int mWifiStandard = ScanResult.WIFI_STANDARD_UNKNOWN;
+
     /**
      * Get the frequency which AP resides on.
      */
@@ -110,7 +153,9 @@
      *
      * @return One of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
      * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ},
-     * {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link #CHANNEL_WIDTH_INVALID}.
+     * {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}, {@link #CHANNEL_WIDTH_2160MHZ},
+     * {@link #CHANNEL_WIDTH_4320MHZ}, {@link #CHANNEL_WIDTH_6480MHZ},
+     * {@link #CHANNEL_WIDTH_8640MHZ}, or {@link #CHANNEL_WIDTH_INVALID}.
      */
     @WifiAnnotations.Bandwidth
     public int getBandwidth() {
@@ -126,12 +171,87 @@
     }
 
     /**
+     * Get the MAC address (BSSID) of the AP. Null when AP disabled.
+     */
+    @Nullable
+    public MacAddress getBssid() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mBssid;
+    }
+
+    /**
+      * Set the MAC address which AP resides on.
+      * <p>
+      * <li>If not set, defaults to null.</li>
+      * @param bssid BSSID, The caller is responsible for avoiding collisions.
+      * @throws IllegalArgumentException when the given BSSID is the all-zero or broadcast MAC
+      *                                  address.
+      *
+      * @hide
+      */
+    public void setBssid(@Nullable MacAddress bssid) {
+        if (bssid != null) {
+            Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS));
+            Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS));
+        }
+        mBssid = bssid;
+    }
+
+    /**
+     * Set the operational mode of the AP.
+     *
+     * @param wifiStandard values from {@link ScanResult}'s {@code WIFI_STANDARD_}
+     * @hide
+     */
+    public void setWifiStandard(@WifiAnnotations.WifiStandard int wifiStandard) {
+        mWifiStandard = wifiStandard;
+    }
+
+    /**
+     * Get the operational mode of the AP.
+     * @return valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
+     */
+    public @WifiAnnotations.WifiStandard int getWifiStandard() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mWifiStandard;
+    }
+
+    /**
+     * Set the AP instance identifier.
+     * @hide
+     */
+    public void setApInstanceIdentifier(@NonNull String apInstanceIdentifier) {
+        mApInstanceIdentifier = apInstanceIdentifier;
+    }
+
+    /**
+     * Get the AP instance identifier.
+     *
+     * The AP instance identifier is a unique identity which can be used to
+     * associate the {@link SoftApInfo} to a specific {@link WifiClient}
+     * - see {@link WifiClient#getApInstanceIdentifier()}
+     *
+     * @hide
+     */
+    @Nullable
+    public String getApInstanceIdentifier() {
+        return mApInstanceIdentifier;
+    }
+
+    /**
      * @hide
      */
     public SoftApInfo(@Nullable SoftApInfo source) {
         if (source != null) {
             mFrequency = source.mFrequency;
             mBandwidth = source.mBandwidth;
+            mBssid = source.mBssid;
+            mWifiStandard = source.mWifiStandard;
+            mApInstanceIdentifier = source.mApInstanceIdentifier;
         }
     }
 
@@ -152,6 +272,9 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mFrequency);
         dest.writeInt(mBandwidth);
+        dest.writeParcelable(mBssid, flags);
+        dest.writeInt(mWifiStandard);
+        dest.writeString(mApInstanceIdentifier);
     }
 
     @NonNull
@@ -161,6 +284,9 @@
             SoftApInfo info = new SoftApInfo();
             info.mFrequency = in.readInt();
             info.mBandwidth = in.readInt();
+            info.mBssid = in.readParcelable(MacAddress.class.getClassLoader());
+            info.mWifiStandard = in.readInt();
+            info.mApInstanceIdentifier = in.readString();
             return info;
         }
 
@@ -172,10 +298,15 @@
     @NonNull
     @Override
     public String toString() {
-        return "SoftApInfo{"
-                + "bandwidth= " + mBandwidth
-                + ",frequency= " + mFrequency
-                + '}';
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append("SoftApInfo{");
+        sbuf.append("bandwidth= ").append(mBandwidth);
+        sbuf.append(", frequency= ").append(mFrequency);
+        if (mBssid != null) sbuf.append(",bssid=").append(mBssid.toString());
+        sbuf.append(", wifiStandard= ").append(mWifiStandard);
+        sbuf.append(", mApInstanceIdentifier= ").append(mApInstanceIdentifier);
+        sbuf.append("}");
+        return sbuf.toString();
     }
 
     @Override
@@ -184,11 +315,14 @@
         if (!(o instanceof SoftApInfo)) return false;
         SoftApInfo softApInfo = (SoftApInfo) o;
         return mFrequency == softApInfo.mFrequency
-                && mBandwidth == softApInfo.mBandwidth;
+                && mBandwidth == softApInfo.mBandwidth
+                && Objects.equals(mBssid, softApInfo.mBssid)
+                && mWifiStandard == softApInfo.mWifiStandard
+                && Objects.equals(mApInstanceIdentifier, softApInfo.mApInstanceIdentifier);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mFrequency, mBandwidth);
+        return Objects.hash(mFrequency, mBandwidth, mBssid, mWifiStandard, mApInstanceIdentifier);
     }
 }
diff --git a/framework/java/android/net/wifi/WifiAnnotations.java b/framework/java/android/net/wifi/WifiAnnotations.java
index acda7e0..807b40b 100644
--- a/framework/java/android/net/wifi/WifiAnnotations.java
+++ b/framework/java/android/net/wifi/WifiAnnotations.java
@@ -57,6 +57,10 @@
             SoftApInfo.CHANNEL_WIDTH_80MHZ,
             SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
             SoftApInfo.CHANNEL_WIDTH_160MHZ,
+            SoftApInfo.CHANNEL_WIDTH_2160MHZ,
+            SoftApInfo.CHANNEL_WIDTH_4320MHZ,
+            SoftApInfo.CHANNEL_WIDTH_6480MHZ,
+            SoftApInfo.CHANNEL_WIDTH_8640MHZ,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Bandwidth {}
@@ -77,6 +81,7 @@
             ScanResult.WIFI_STANDARD_11N,
             ScanResult.WIFI_STANDARD_11AC,
             ScanResult.WIFI_STANDARD_11AX,
+            ScanResult.WIFI_STANDARD_11AD,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface WifiStandard{}
diff --git a/framework/java/android/net/wifi/WifiClient.java b/framework/java/android/net/wifi/WifiClient.java
index 3794566..85e2b33 100644
--- a/framework/java/android/net/wifi/WifiClient.java
+++ b/framework/java/android/net/wifi/WifiClient.java
@@ -30,6 +30,9 @@
 
     private final MacAddress mMacAddress;
 
+    /** The identifier of the AP instance which the client connected. */
+    private final String mApInstanceIdentifier;
+
     /**
      * The mac address of this client.
      */
@@ -38,15 +41,30 @@
         return mMacAddress;
     }
 
+    /**
+     * Get AP instance identifier.
+     *
+     * The AP instance identifier is a unique identity which can be used to
+     * associate the {@link SoftApInfo} to a specific {@link WifiClient}
+     * - see {@link SoftApInfo#getApInstanceIdentifier()}
+     * @hide
+     */
+    @NonNull
+    public String getApInstanceIdentifier() {
+        return mApInstanceIdentifier;
+    }
+
     private WifiClient(Parcel in) {
         mMacAddress = in.readParcelable(null);
+        mApInstanceIdentifier = in.readString();
     }
 
     /** @hide */
-    public WifiClient(@NonNull MacAddress macAddress) {
+    public WifiClient(@NonNull MacAddress macAddress, @NonNull String apInstanceIdentifier) {
         Objects.requireNonNull(macAddress, "mMacAddress must not be null.");
 
         this.mMacAddress = macAddress;
+        this.mApInstanceIdentifier = apInstanceIdentifier;
     }
 
     @Override
@@ -57,6 +75,7 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeParcelable(mMacAddress, flags);
+        dest.writeString(mApInstanceIdentifier);
     }
 
     @NonNull
@@ -75,6 +94,7 @@
     public String toString() {
         return "WifiClient{"
                 + "mMacAddress=" + mMacAddress
+                + "mApInstanceIdentifier=" + mApInstanceIdentifier
                 + '}';
     }
 
@@ -83,13 +103,12 @@
         if (this == o) return true;
         if (!(o instanceof WifiClient)) return false;
         WifiClient client = (WifiClient) o;
-        return mMacAddress.equals(client.mMacAddress);
+        return Objects.equals(mMacAddress, client.mMacAddress)
+                && mApInstanceIdentifier.equals(client.mApInstanceIdentifier);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mMacAddress);
+        return Objects.hash(mMacAddress, mApInstanceIdentifier);
     }
 }
-
-
diff --git a/framework/java/android/net/wifi/WifiConfiguration.java b/framework/java/android/net/wifi/WifiConfiguration.java
index 93c6358..6c0b2df 100644
--- a/framework/java/android/net/wifi/WifiConfiguration.java
+++ b/framework/java/android/net/wifi/WifiConfiguration.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.PackageManager;
@@ -34,6 +35,8 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -44,10 +47,13 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * A class representing a configured Wi-Fi network, including the
@@ -248,6 +254,11 @@
          */
         public static final int WAPI = 3;
 
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {WPA, RSN, OSEN, WAPI})
+        public @interface ProtocolScheme {};
+
         public static final String varName = "proto";
 
         public static final String[] strings = { "WPA", "RSN", "OSEN", "WAPI" };
@@ -272,6 +283,11 @@
         /** SAE (Used only for WPA3-Personal) */
         public static final int SAE = 3;
 
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {OPEN, SHARED, LEAP, SAE})
+        public @interface AuthAlgorithmScheme {};
+
         public static final String varName = "auth_alg";
 
         public static final String[] strings = { "OPEN", "SHARED", "LEAP", "SAE" };
@@ -301,9 +317,20 @@
          */
         public static final int SMS4 = 4;
 
+        /**
+         * AES in Galois/Counter Mode with a 128-bit integrity key
+         */
+        public static final int GCMP_128 = 5;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {NONE, TKIP, CCMP, GCMP_256, SMS4, GCMP_128})
+        public @interface PairwiseCipherScheme {};
+
         public static final String varName = "pairwise";
 
-        public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256", "SMS4" };
+        public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256", "SMS4",
+                "GCMP_128" };
     }
 
     /**
@@ -345,13 +372,22 @@
          * SMS4 cipher for WAPI
          */
         public static final int SMS4 = 6;
+        /**
+         * AES in Galois/Counter Mode with a 128-bit integrity key
+         */
+        public static final int GCMP_128 = 7;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {WEP40, WEP104, TKIP, CCMP, GTK_NOT_USED, GCMP_256, SMS4, GCMP_128})
+        public @interface GroupCipherScheme {};
 
         public static final String varName = "group";
 
         public static final String[] strings =
                 { /* deprecated */ "WEP40", /* deprecated */ "WEP104",
                         "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256",
-                        "SMS4" };
+                        "SMS4", "GCMP_128" };
     }
 
     /**
@@ -374,9 +410,16 @@
         /** GMAC-256 = Galois Message Authentication Code */
         public static final int BIP_GMAC_256 = 2;
 
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {BIP_CMAC_256, BIP_GMAC_128, BIP_GMAC_256})
+        public @interface GroupMgmtCipherScheme {};
+
         private static final String varName = "groupMgmt";
 
-        private static final String[] strings = { "BIP_CMAC_256",
+        /** @hide */
+        @SuppressLint("AllUpper")
+        public static final @NonNull String[] strings = { "BIP_CMAC_256",
                 "BIP_GMAC_128", "BIP_GMAC_256"};
     }
 
@@ -397,9 +440,16 @@
         /** Diffie-Hellman with_RSA signature */
         public static final int ECDHE_RSA = 1;
 
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(value = {ECDHE_ECDSA, ECDHE_RSA})
+        public @interface SuiteBCipherScheme {};
+
         private static final String varName = "SuiteB";
 
-        private static final String[] strings = { "ECDHE_ECDSA", "ECDHE_RSA" };
+        /** @hide */
+        @SuppressLint("AllUpper")
+        public static final String[] strings = { "ECDHE_ECDSA", "ECDHE_RSA" };
     }
 
     /** Possible status of a network configuration. */
@@ -426,14 +476,46 @@
     public static final int SECURITY_TYPE_EAP = 3;
     /** Security type for an SAE network. */
     public static final int SECURITY_TYPE_SAE = 4;
-    /** Security type for an EAP Suite B network. */
-    public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
+    /**
+     * Security type for a WPA3-Enterprise in 192-bit security network.
+     * This is the same as {@link #SECURITY_TYPE_EAP_SUITE_B} and uses the same value.
+     */
+    public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT = 5;
+    /**
+     * Security type for a WPA3-Enterprise in 192-bit security network.
+     * @deprecated Use the {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT} constant
+     * (which is the same value).
+     */
+    @Deprecated
+    public static final int SECURITY_TYPE_EAP_SUITE_B =
+            SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
     /** Security type for an OWE network. */
     public static final int SECURITY_TYPE_OWE = 6;
     /** Security type for a WAPI PSK network. */
     public static final int SECURITY_TYPE_WAPI_PSK = 7;
     /** Security type for a WAPI Certificate network. */
     public static final int SECURITY_TYPE_WAPI_CERT = 8;
+    /** Security type for a WPA3-Enterprise network. */
+    public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE = 9;
+    /**
+     * Security type for an OSEN network.
+     * @hide
+     */
+    public static final int SECURITY_TYPE_OSEN = 10;
+    /**
+     * Security type for a Passpoint R1/R2 network.
+     * Passpoint R1/R2 uses Enterprise security, where TKIP and WEP are not allowed.
+     * @hide
+     */
+    public static final int SECURITY_TYPE_PASSPOINT_R1_R2 = 11;
+
+    /**
+     * Security type for a Passpoint R3 network.
+     * Passpoint R3 uses Enterprise security, where TKIP and WEP are not allowed,
+     * and PMF must be set to Required.
+     * @hide
+     */
+    public static final int SECURITY_TYPE_PASSPOINT_R3 = 12;
 
     /**
      * Security types we support.
@@ -449,13 +531,92 @@
             SECURITY_TYPE_EAP_SUITE_B,
             SECURITY_TYPE_OWE,
             SECURITY_TYPE_WAPI_PSK,
-            SECURITY_TYPE_WAPI_CERT
+            SECURITY_TYPE_WAPI_CERT,
+            SECURITY_TYPE_EAP_WPA3_ENTERPRISE,
+            SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
+            SECURITY_TYPE_PASSPOINT_R1_R2,
+            SECURITY_TYPE_PASSPOINT_R3,
     })
     public @interface SecurityType {}
 
+    private List<SecurityParams> mSecurityParamsList = new ArrayList<>();
+
+    private void updateLegacySecurityParams() {
+        if (mSecurityParamsList.isEmpty()) return;
+        mSecurityParamsList.get(0).updateLegacyWifiConfiguration(this);
+    }
+
     /**
      * Set the various security params to correspond to the provided security type.
      * This is accomplished by setting the various BitSets exposed in WifiConfiguration.
+     * <br>
+     * This API would clear existing security types and add a default one.
+     *
+     * @param securityType One of the following security types:
+     * {@link #SECURITY_TYPE_OPEN},
+     * {@link #SECURITY_TYPE_WEP},
+     * {@link #SECURITY_TYPE_PSK},
+     * {@link #SECURITY_TYPE_EAP},
+     * {@link #SECURITY_TYPE_SAE},
+     * {@link #SECURITY_TYPE_OWE},
+     * {@link #SECURITY_TYPE_WAPI_PSK},
+     * {@link #SECURITY_TYPE_WAPI_CERT},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT},
+     */
+    public void setSecurityParams(@SecurityType int securityType) {
+        // Clear existing data.
+        mSecurityParamsList.clear();
+        addSecurityParams(securityType);
+    }
+
+    /**
+     * Set security params by the given key management mask.
+     *
+     * @param givenAllowedKeyManagement the given allowed key management mask.
+     * @hide
+     */
+    public void setSecurityParams(@NonNull BitSet givenAllowedKeyManagement) {
+        if (givenAllowedKeyManagement == null) {
+            throw new IllegalArgumentException("Invalid allowed key management mask.");
+        }
+        // Clear existing data.
+        mSecurityParamsList.clear();
+
+        allowedKeyManagement = (BitSet) givenAllowedKeyManagement.clone();
+        convertLegacyFieldsToSecurityParamsIfNeeded();
+    }
+
+    /**
+     * Add the various security params.
+     * <br>
+     * This API would clear existing security types and add a default one.
+     * @hide
+     */
+    public void setSecurityParams(SecurityParams params) {
+        // Clear existing data.
+        mSecurityParamsList.clear();
+        addSecurityParams(params);
+    }
+
+    /**
+     * Set the security params by the given security params list.
+     *
+     * This will overwrite existing security params list directly.
+     *
+     * @param securityParamsList the desired security params list.
+     * @hide
+     */
+    public void setSecurityParams(@NonNull List<SecurityParams> securityParamsList) {
+        if (securityParamsList == null || securityParamsList.isEmpty()) {
+            throw new IllegalArgumentException("An empty security params list is invalid.");
+        }
+        mSecurityParamsList = new ArrayList<>(securityParamsList);
+    }
+
+    /**
+     * Add the various security params to correspond to the provided security type.
+     * This is accomplished by setting the various BitSets exposed in WifiConfiguration.
      *
      * @param securityType One of the following security types:
      * {@link #SECURITY_TYPE_OPEN},
@@ -463,82 +624,276 @@
      * {@link #SECURITY_TYPE_PSK},
      * {@link #SECURITY_TYPE_EAP},
      * {@link #SECURITY_TYPE_SAE},
-     * {@link #SECURITY_TYPE_EAP_SUITE_B},
      * {@link #SECURITY_TYPE_OWE},
-     * {@link #SECURITY_TYPE_WAPI_PSK}, or
-     * {@link #SECURITY_TYPE_WAPI_CERT}
+     * {@link #SECURITY_TYPE_WAPI_PSK},
+     * {@link #SECURITY_TYPE_WAPI_CERT},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT},
+     *
+     * @hide
      */
-    public void setSecurityParams(@SecurityType int securityType) {
-        // Clear all the bitsets.
-        allowedKeyManagement.clear();
-        allowedProtocols.clear();
-        allowedAuthAlgorithms.clear();
-        allowedPairwiseCiphers.clear();
-        allowedGroupCiphers.clear();
-        allowedGroupManagementCiphers.clear();
-        allowedSuiteBCiphers.clear();
-
-        switch (securityType) {
-            case SECURITY_TYPE_OPEN:
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
-                break;
-            case SECURITY_TYPE_WEP:
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
-                allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
-                allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
-                break;
-            case SECURITY_TYPE_PSK:
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
-                break;
-            case SECURITY_TYPE_EAP:
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
-                break;
-            case SECURITY_TYPE_SAE:
-                allowedProtocols.set(WifiConfiguration.Protocol.RSN);
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
-                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
-                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
-                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
-                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
-                requirePmf = true;
-                break;
-            case SECURITY_TYPE_EAP_SUITE_B:
-                allowedProtocols.set(WifiConfiguration.Protocol.RSN);
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
-                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
-                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
-                allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
-                // Note: allowedSuiteBCiphers bitset will be set by the service once the
-                // certificates are attached to this profile
-                requirePmf = true;
-                break;
-            case SECURITY_TYPE_OWE:
-                allowedProtocols.set(WifiConfiguration.Protocol.RSN);
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
-                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
-                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
-                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
-                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
-                requirePmf = true;
-                break;
-            case SECURITY_TYPE_WAPI_PSK:
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_PSK);
-                allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
-                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
-                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
-                break;
-            case SECURITY_TYPE_WAPI_CERT:
-                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_CERT);
-                allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
-                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
-                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
-                break;
-            default:
-                throw new IllegalArgumentException("unknown security type " + securityType);
+    public void addSecurityParams(@SecurityType int securityType) {
+        // This ensures that there won't be duplicate security types.
+        if (mSecurityParamsList.stream().anyMatch(params -> params.isSecurityType(securityType))) {
+            throw new IllegalArgumentException("duplicate security type " + securityType);
         }
+        addSecurityParams(SecurityParams.createSecurityParamsBySecurityType(securityType));
+    }
+
+    /** @hide */
+    public void addSecurityParams(@NonNull SecurityParams newParams) {
+        if (mSecurityParamsList.stream().anyMatch(params -> params.isSameSecurityType(newParams))) {
+            throw new IllegalArgumentException("duplicate security params " + newParams);
+        }
+        if (!mSecurityParamsList.isEmpty()) {
+            if (newParams.isEnterpriseSecurityType() && !isEnterprise()) {
+                throw new IllegalArgumentException(
+                        "An enterprise security type cannot be added to a personal configuation.");
+            }
+            if (!newParams.isEnterpriseSecurityType() && isEnterprise()) {
+                throw new IllegalArgumentException(
+                        "A personal security type cannot be added to an enterprise configuation.");
+            }
+            if (newParams.isOpenSecurityType() && !isOpenNetwork()) {
+                throw new IllegalArgumentException(
+                        "An open security type cannot be added to a non-open configuation.");
+            }
+            if (!newParams.isOpenSecurityType() && isOpenNetwork()) {
+                throw new IllegalArgumentException(
+                        "A non-open security type cannot be added to an open configuation.");
+            }
+            if (newParams.isSecurityType(SECURITY_TYPE_OSEN)) {
+                throw new IllegalArgumentException(
+                        "An OSEN security type must be the only one type.");
+            }
+        }
+        mSecurityParamsList.add(new SecurityParams(newParams));
+        updateLegacySecurityParams();
+    }
+
+    /**
+     * If there is no security params, generate one according to legacy fields.
+     * @hide
+     */
+    public void convertLegacyFieldsToSecurityParamsIfNeeded() {
+        if (!mSecurityParamsList.isEmpty()) return;
+
+        if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
+            setSecurityParams(SECURITY_TYPE_WAPI_CERT);
+        } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
+            setSecurityParams(SECURITY_TYPE_WAPI_PSK);
+        } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+            setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
+        } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
+            setSecurityParams(SECURITY_TYPE_OWE);
+        } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
+            setSecurityParams(SECURITY_TYPE_SAE);
+        } else if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
+            setSecurityParams(SECURITY_TYPE_OSEN);
+        } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
+            setSecurityParams(SECURITY_TYPE_PSK);
+        } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
+            if (requirePmf) {
+                setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+            } else {
+                setSecurityParams(SECURITY_TYPE_EAP);
+            }
+        } else if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+            setSecurityParams(SECURITY_TYPE_PSK);
+        } else if (allowedKeyManagement.get(KeyMgmt.NONE)) {
+            if (hasWepKeys()) {
+                setSecurityParams(SECURITY_TYPE_WEP);
+            } else {
+                setSecurityParams(SECURITY_TYPE_OPEN);
+            }
+        } else {
+            setSecurityParams(SECURITY_TYPE_OPEN);
+        }
+    }
+
+    /**
+     * Disable the various security params to correspond to the provided security type.
+     * This is accomplished by setting the various BitSets exposed in WifiConfiguration.
+     *
+     * @param securityType One of the following security types:
+     * {@link #SECURITY_TYPE_OPEN},
+     * {@link #SECURITY_TYPE_WEP},
+     * {@link #SECURITY_TYPE_PSK},
+     * {@link #SECURITY_TYPE_EAP},
+     * {@link #SECURITY_TYPE_SAE},
+     * {@link #SECURITY_TYPE_OWE},
+     * {@link #SECURITY_TYPE_WAPI_PSK},
+     * {@link #SECURITY_TYPE_WAPI_CERT},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT},
+     *
+     * @hide
+     */
+    public void setSecurityParamsEnabled(@SecurityType int securityType, boolean enable) {
+        mSecurityParamsList.stream()
+                .filter(params -> params.isSecurityType(securityType))
+                .findAny()
+                .ifPresent(params -> params.setEnabled(enable));
+    }
+
+    /**
+     * Get the specific security param.
+     *
+     * @param securityType One of the following security types:
+     * {@link #SECURITY_TYPE_OPEN},
+     * {@link #SECURITY_TYPE_WEP},
+     * {@link #SECURITY_TYPE_PSK},
+     * {@link #SECURITY_TYPE_EAP},
+     * {@link #SECURITY_TYPE_SAE},
+     * {@link #SECURITY_TYPE_OWE},
+     * {@link #SECURITY_TYPE_WAPI_PSK},
+     * {@link #SECURITY_TYPE_WAPI_CERT},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT},
+     *
+     * @return the copy of specific security params if found; otherwise null.
+     * @hide
+     */
+    public @Nullable SecurityParams getSecurityParams(@SecurityType int securityType) {
+        SecurityParams p = mSecurityParamsList.stream()
+                .filter(params -> params.isSecurityType(securityType))
+                .findAny()
+                .orElse(null);
+        return (p != null) ? new SecurityParams(p) : null;
+    }
+
+    /**
+     * Indicate whether this configuration is the specific security type.
+     *
+     * @param securityType One of the following security types:
+     * {@link #SECURITY_TYPE_OPEN},
+     * {@link #SECURITY_TYPE_WEP},
+     * {@link #SECURITY_TYPE_PSK},
+     * {@link #SECURITY_TYPE_EAP},
+     * {@link #SECURITY_TYPE_SAE},
+     * {@link #SECURITY_TYPE_OWE},
+     * {@link #SECURITY_TYPE_WAPI_PSK},
+     * {@link #SECURITY_TYPE_WAPI_CERT},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+     * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT},
+     *
+     * @return true if there is a security params matches the type.
+     * @hide
+     */
+    public boolean isSecurityType(@SecurityType int securityType) {
+        return mSecurityParamsList.stream()
+                .anyMatch(params -> params.isSecurityType(securityType));
+    }
+
+    /**
+     * Get the security params list of this configuration.
+     *
+     * The returning list is a priority list, the first is the lowest priority and default one.
+     *
+     * @return this list of security params.
+     * @hide
+     */
+    public List<SecurityParams> getSecurityParamsList() {
+        return Collections.unmodifiableList(mSecurityParamsList);
+    }
+
+    /**
+     * Enable the support of Fast Initial Link Set-up (FILS).
+     *
+     * FILS can be applied to all security types.
+     * @param enableFilsSha256 Enable FILS SHA256.
+     * @param enableFilsSha384 Enable FILS SHA256.
+     * @hide
+     */
+    public void enableFils(boolean enableFilsSha256, boolean enableFilsSha384) {
+        mSecurityParamsList.stream()
+                .forEach(params -> params.enableFils(enableFilsSha256, enableFilsSha384));
+        updateLegacySecurityParams();
+    }
+
+    /**
+     * Indicate FILS SHA256 is enabled.
+     *
+     * @return true if FILS SHA256 is enabled.
+     * @hide
+     */
+    public boolean isFilsSha256Enabled() {
+        return mSecurityParamsList.stream()
+                .anyMatch(params -> params.getAllowedKeyManagement().get(KeyMgmt.FILS_SHA256));
+    }
+
+    /**
+     * Indicate FILS SHA384 is enabled.
+     *
+     * @return true if FILS SHA384 is enabled.
+     * @hide
+     */
+    public boolean isFilsSha384Enabled() {
+        return mSecurityParamsList.stream()
+                .anyMatch(params -> params.getAllowedKeyManagement().get(KeyMgmt.FILS_SHA384));
+    }
+
+    /**
+     * Enable Suite-B ciphers.
+     *
+     * @param enableEcdheEcdsa enable Diffie-Hellman with Elliptic Curve ECDSA cipher support.
+     * @param enableEcdheRsa enable Diffie-Hellman with RSA cipher support.
+     * @hide
+     */
+    public void enableSuiteBCiphers(boolean enableEcdheEcdsa, boolean enableEcdheRsa) {
+        mSecurityParamsList.stream()
+                .filter(params -> params.isSecurityType(SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT))
+                .findAny()
+                .ifPresent(params -> params.enableSuiteBCiphers(enableEcdheEcdsa, enableEcdheRsa));
+        updateLegacySecurityParams();
+    }
+
+    /**
+     * Indicate ECDHE_ECDSA is enabled.
+     *
+     * @return true if enabled.
+     * @hide
+     */
+    public boolean isSuiteBCipherEcdheEcdsaEnabled() {
+        return mSecurityParamsList.stream()
+                .anyMatch(params -> params.getAllowedSuiteBCiphers().get(SuiteBCipher.ECDHE_ECDSA));
+    }
+
+    /**
+     * Indicate ECDHE_RSA is enabled.
+     *
+     * @return true if enabled.
+     * @hide
+     */
+    public boolean isSuiteBCipherEcdheRsaEnabled() {
+        return mSecurityParamsList.stream()
+                .anyMatch(params -> params.getAllowedSuiteBCiphers().get(SuiteBCipher.ECDHE_RSA));
+    }
+
+    /**
+     * Set SAE Hash-toElement only mode enabled.
+     *
+     * @param enable true if enabled; false otherwise.
+     * @hide
+     */
+    public void enableSaeH2eOnlyMode(boolean enable) {
+        mSecurityParamsList.stream()
+                .filter(params -> params.isSecurityType(SECURITY_TYPE_SAE))
+                .findAny()
+                .ifPresent(params -> params.enableSaeH2eOnlyMode(enable));
+    }
+
+    /**
+     * Set SAE Public-Key only mode enabled.
+     *
+     * @param enable true if enabled; false otherwise.
+     * @hide
+     */
+    public void enableSaePkOnlyMode(boolean enable) {
+        mSecurityParamsList.stream()
+                .filter(params -> params.isSecurityType(SECURITY_TYPE_SAE))
+                .findAny()
+                .ifPresent(params -> params.enableSaePkOnlyMode(enable));
     }
 
     /** @hide */
@@ -596,6 +951,12 @@
     public static final int AP_BAND_5GHZ = 1;
 
     /**
+     * 60GHz band
+     * @hide
+     */
+    public static final int AP_BAND_60GHZ = 2;
+
+    /**
      * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
      * operating country code and current radio conditions.
      * @hide
@@ -858,6 +1219,14 @@
     public int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
 
     /**
+     * The subscription ID identifies the SIM card for which this network configuration is valid.
+     * See {@link SubscriptionInfo#getSubscriptionId()}
+     * @hide
+     */
+    @SystemApi
+    public int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+    /**
      * @hide
      * Auto-join is allowed by user for this network.
      * Default true.
@@ -969,6 +1338,36 @@
     public boolean trusted;
 
     /**
+     * Indicate whether the network is oem paid or not. Networks are considered oem paid
+     * if the corresponding connection is only available to system apps.
+     *
+     * This bit can only be used by suggestion network, see
+     * {@link WifiNetworkSuggestion.Builder#setOemPaid(boolean)}
+     * @hide
+     */
+    public boolean oemPaid;
+
+
+    /**
+     * Indicate whether the network is oem private or not. Networks are considered oem private
+     * if the corresponding connection is only available to system apps.
+     *
+     * This bit can only be used by suggestion network, see
+     * {@link WifiNetworkSuggestion.Builder#setOemPrivate(boolean)}
+     * @hide
+     */
+    public boolean oemPrivate;
+
+    /**
+     * Indicate whether or not the network is a carrier merged network.
+     * This bit can only be used by suggestion network, see
+     * {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
+     * @hide
+     */
+    @SystemApi
+    public boolean carrierMerged;
+
+    /**
      * True if this Wifi configuration is created from a {@link WifiNetworkSuggestion},
      * false otherwise.
      *
@@ -1068,27 +1467,25 @@
         return metered;
     }
 
-    /**
-     * @hide
-     * Returns true if this WiFi config is for an open network.
-     */
-    public boolean isOpenNetwork() {
-        final int cardinality = allowedKeyManagement.cardinality();
-        final boolean hasNoKeyMgmt = cardinality == 0
-                || (cardinality == 1 && (allowedKeyManagement.get(KeyMgmt.NONE)
-                || allowedKeyManagement.get(KeyMgmt.OWE)));
-
-        boolean hasNoWepKeys = true;
-        if (wepKeys != null) {
-            for (int i = 0; i < wepKeys.length; i++) {
-                if (wepKeys[i] != null) {
-                    hasNoWepKeys = false;
-                    break;
-                }
+    /** Check whether wep keys exist. */
+    private boolean hasWepKeys() {
+        if (wepKeys == null) return false;
+        for (int i = 0; i < wepKeys.length; i++) {
+            if (wepKeys[i] != null) {
+                return true;
             }
         }
+        return false;
+    }
 
-        return hasNoKeyMgmt && hasNoWepKeys;
+    /**
+     * @hide
+     * Returns true if this WiFi config is for an Open or Enhanced Open network.
+     */
+    public boolean isOpenNetwork() {
+        boolean hasNonOpenSecurityType = mSecurityParamsList.stream()
+                .anyMatch(params -> !params.isOpenSecurityType());
+        return !hasNonOpenSecurityType && !hasWepKeys();
     }
 
     /**
@@ -1130,7 +1527,9 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"RANDOMIZATION_"}, value = {
             RANDOMIZATION_NONE,
-            RANDOMIZATION_PERSISTENT})
+            RANDOMIZATION_PERSISTENT,
+            RANDOMIZATION_ENHANCED,
+            RANDOMIZATION_AUTO})
     public @interface MacRandomizationSetting {}
 
     /**
@@ -1147,14 +1546,30 @@
     public static final int RANDOMIZATION_PERSISTENT = 1;
 
     /**
+     * Use a randomly generated MAC address for connections to this network.
+     * This option does not persist the randomized MAC address.
+     * @hide
+     */
+    @SystemApi
+    public static final int RANDOMIZATION_ENHANCED = 2;
+
+    /**
+     * Let the wifi framework automatically decide the MAC randomization strategy.
+     * @hide
+     */
+    @SystemApi
+    public static final int RANDOMIZATION_AUTO = 3;
+
+    /**
      * Level of MAC randomization for this network.
-     * One of {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}.
-     * By default this field is set to {@link #RANDOMIZATION_PERSISTENT}.
+     * One of {@link #RANDOMIZATION_NONE}, {@link #RANDOMIZATION_AUTO},
+     * {@link #RANDOMIZATION_PERSISTENT} or {@link #RANDOMIZATION_ENHANCED}.
+     * By default this field is set to {@link #RANDOMIZATION_AUTO}.
      * @hide
      */
     @SystemApi
     @MacRandomizationSetting
-    public int macRandomizationSetting = RANDOMIZATION_PERSISTENT;
+    public int macRandomizationSetting = RANDOMIZATION_AUTO;
 
     /**
      * @hide
@@ -1165,12 +1580,18 @@
 
     /**
      * @hide
-     * The wall clock time of when |mRandomizedMacAddress| should be re-randomized in aggressive
-     * randomization mode.
+     * The wall clock time of when |mRandomizedMacAddress| should be re-randomized in enhanced
+     * MAC randomization mode.
      */
     public long randomizedMacExpirationTimeMs = 0;
 
     /**
+     * The wall clock time of when |mRandomizedMacAddress| is last modified.
+     * @hide
+     */
+    public long randomizedMacLastModifiedTimeMs = 0;
+
+    /**
      * @hide
      * Checks if the given MAC address can be used for Connected Mac Randomization
      * by verifying that it is non-null, unicast, locally assigned, and not default mac.
@@ -1271,7 +1692,9 @@
                 DISABLED_NO_INTERNET_PERMANENT,
                 DISABLED_BY_WIFI_MANAGER,
                 DISABLED_BY_WRONG_PASSWORD,
-                DISABLED_AUTHENTICATION_NO_SUBSCRIPTION})
+                DISABLED_AUTHENTICATION_NO_SUBSCRIPTION,
+                DISABLED_AUTHENTICATION_FAILURE_GENERIC,
+                DISABLED_AUTHENTICATION_FAILURE_CARRIER_SPECIFIC})
         public @interface NetworkSelectionDisableReason {}
 
         // Quality Network disabled reasons
@@ -1282,42 +1705,42 @@
          * @hide
          */
         public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1;
-        /**
-         * The starting index for network selection temporarily disabled reasons.
-         * @hide
-         */
-        public static final int TEMPORARILY_DISABLED_STARTING_INDEX = 1;
-        /** This network is disabled because of multiple association rejections. */
+        /** This network is temporarily disabled because of multiple association rejections. */
         public static final int DISABLED_ASSOCIATION_REJECTION = 1;
-        /** This network is disabled because of multiple authentication failure. */
-        public static final int DISABLED_AUTHENTICATION_FAILURE = 2;
-        /** This network is disabled because of multiple DHCP failure. */
+        /** This network is disabled due to generic authentication failure. */
+        public static final int DISABLED_AUTHENTICATION_FAILURE_GENERIC = 2;
+        /** Separate DISABLED_AUTHENTICATION_FAILURE into DISABLED_AUTHENTICATION_FAILURE_GENERIC
+         *  and DISABLED_AUTHENTICATION_FAILURE_CARRIER_SPECIFIC
+         *  @deprecated Use the {@link #DISABLED_AUTHENTICATION_FAILURE_GENERIC} constant
+         * (which is the same value).
+         */
+        @Deprecated
+        public static final int DISABLED_AUTHENTICATION_FAILURE =
+                DISABLED_AUTHENTICATION_FAILURE_GENERIC;
+        /** This network is temporarily disabled because of multiple DHCP failure. */
         public static final int DISABLED_DHCP_FAILURE = 3;
         /** This network is temporarily disabled because it has no Internet access. */
         public static final int DISABLED_NO_INTERNET_TEMPORARY = 4;
-        /**
-         * The starting index for network selection permanently disabled reasons.
-         * @hide
-         */
-        public static final int PERMANENTLY_DISABLED_STARTING_INDEX = 5;
-        /** This network is disabled due to absence of user credentials */
+        /** This network is permanently disabled due to absence of user credentials */
         public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5;
         /**
          * This network is permanently disabled because it has no Internet access and the user does
          * not want to stay connected.
          */
         public static final int DISABLED_NO_INTERNET_PERMANENT = 6;
-        /** This network is disabled due to WifiManager disabling it explicitly. */
+        /** This network is permanently disabled due to WifiManager disabling it explicitly. */
         public static final int DISABLED_BY_WIFI_MANAGER = 7;
-        /** This network is disabled due to wrong password. */
+        /** This network is permanently disabled due to wrong password. */
         public static final int DISABLED_BY_WRONG_PASSWORD = 8;
-        /** This network is disabled because service is not subscribed. */
+        /** This network is permanently disabled because service is not subscribed. */
         public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9;
+        /** This network is disabled due to carrier specific EAP failure. */
+        public static final int DISABLED_AUTHENTICATION_FAILURE_CARRIER_SPECIFIC = 10;
         /**
          * All other disable reasons should be strictly less than this value.
          * @hide
          */
-        public static final int NETWORK_SELECTION_DISABLED_MAX = 10;
+        public static final int NETWORK_SELECTION_DISABLED_MAX = 11;
 
         /**
          * Get an integer that is equal to the maximum integer value of all the
@@ -1361,6 +1784,8 @@
             /**
              * Network Selection disable timeout for the error. After the timeout milliseconds,
              * enable the network again.
+             * If this is set to Integer.MAX_VALUE, the network will be permanently disabled until
+             * the next time the user manually connects to it.
              */
             public final int mDisableTimeoutMillis;
 
@@ -1455,6 +1880,18 @@
                             1,
                             Integer.MAX_VALUE));
 
+            reasons.append(DISABLED_AUTHENTICATION_FAILURE_GENERIC,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE_GENERIC",
+                            5,
+                            5 * 60 * 1000));
+
+            reasons.append(DISABLED_AUTHENTICATION_FAILURE_CARRIER_SPECIFIC,
+                    new DisableReasonInfo(
+                            "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE_CARRIER_SPECIFIC",
+                            1,
+                            Integer.MAX_VALUE));
+
             return reasons;
         }
 
@@ -1529,6 +1966,11 @@
         private String mConnectChoice;
 
         /**
+         * The RSSI when the user made the connectChoice.
+         */
+        private int mConnectChoiceRssi;
+
+        /**
          * Used to cache the temporary candidate during the network selection procedure. It will be
          * kept updating once a new scan result has a higher score than current one
          */
@@ -1559,6 +2001,14 @@
         private boolean mHasEverConnected;
 
         /**
+         * Boolean indicating if captive portal has never been detected on this network.
+         *
+         * This should be true by default, for newly created WifiConfigurations until a captive
+         * portal is detected.
+         */
+        private boolean mHasNeverDetectedCaptivePortal = true;
+
+        /**
          * set whether this network is visible in latest Qualified Network Selection
          * @param seen value set to candidate
          * @hide
@@ -1631,6 +2081,23 @@
             mConnectChoice = newConnectChoice;
         }
 
+        /**
+         * Associate a RSSI with the user connect choice network.
+         * @param rssi signal strength
+         * @hide
+         */
+        public void setConnectChoiceRssi(int rssi) {
+            mConnectChoiceRssi = rssi;
+        }
+
+        /**
+         * @return returns the RSSI of the last time the user made the connect choice.
+         * @hide
+         */
+        public int getConnectChoiceRssi() {
+            return mConnectChoiceRssi;
+        }
+
         /** Get the current Quality network selection status as a String (for debugging). */
         @NonNull
         public String getNetworkStatusString() {
@@ -1647,6 +2114,19 @@
             return mHasEverConnected;
         }
 
+        /**
+         * Set whether a captive portal has never been detected on this network.
+         * @hide
+         */
+        public void setHasNeverDetectedCaptivePortal(boolean value) {
+            mHasNeverDetectedCaptivePortal = value;
+        }
+
+        /** @hide */
+        public boolean hasNeverDetectedCaptivePortal() {
+            return mHasNeverDetectedCaptivePortal;
+        }
+
         /** @hide */
         public NetworkSelectionStatus() {
             // previously stored configs will not have this parameter, so we default to false.
@@ -1921,7 +2401,9 @@
             setCandidate(source.getCandidate());
             setCandidateScore(source.getCandidateScore());
             setConnectChoice(source.getConnectChoice());
+            setConnectChoiceRssi(source.getConnectChoiceRssi());
             setHasEverConnected(source.hasEverConnected());
+            setHasNeverDetectedCaptivePortal(source.hasNeverDetectedCaptivePortal());
         }
 
         /** @hide */
@@ -1937,10 +2419,12 @@
             if (getConnectChoice() != null) {
                 dest.writeInt(CONNECT_CHOICE_EXISTS);
                 dest.writeString(getConnectChoice());
+                dest.writeInt(getConnectChoiceRssi());
             } else {
                 dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
             }
             dest.writeInt(hasEverConnected() ? 1 : 0);
+            dest.writeInt(hasNeverDetectedCaptivePortal() ? 1 : 0);
         }
 
         /** @hide */
@@ -1955,10 +2439,12 @@
             setNetworkSelectionBSSID(in.readString());
             if (in.readInt() == CONNECT_CHOICE_EXISTS) {
                 setConnectChoice(in.readString());
+                setConnectChoiceRssi(in.readInt());
             } else {
                 setConnectChoice(null);
             }
             setHasEverConnected(in.readInt() != 0);
+            setHasNeverDetectedCaptivePortal(in.readInt() != 0);
         }
     }
 
@@ -1983,27 +2469,42 @@
          */
         @RecentFailureReason
         private int mAssociationStatus = RECENT_FAILURE_NONE;
+        private long mLastUpdateTimeSinceBootMillis;
 
         /**
          * @param status the association status code for the recent failure
          */
-        public void setAssociationStatus(@RecentFailureReason int status) {
+        public void setAssociationStatus(@RecentFailureReason int status,
+                long updateTimeSinceBootMs) {
             mAssociationStatus = status;
+            mLastUpdateTimeSinceBootMillis = updateTimeSinceBootMs;
         }
         /**
          * Sets the RecentFailure to NONE
          */
         public void clear() {
             mAssociationStatus = RECENT_FAILURE_NONE;
+            mLastUpdateTimeSinceBootMillis = 0;
         }
         /**
-         * Get the recent failure code. One of {@link #RECENT_FAILURE_NONE} or
-         * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}.
+         * Get the recent failure code. One of {@link #RECENT_FAILURE_NONE},
+         * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA},
+         * {@link #RECENT_FAILURE_MBO_OCE_DISCONNECT},
+         * {@link #RECENT_FAILURE_REFUSED_TEMPORARILY},
+         * {@link #RECENT_FAILURE_POOR_CHANNEL_CONDITIONS}.
+         * {@link #RECENT_FAILURE_DISCONNECTION_AP_BUSY}
          */
         @RecentFailureReason
         public int getAssociationStatus() {
             return mAssociationStatus;
         }
+
+        /**
+         * Get the timestamp the failure status is last updated, in milliseconds since boot.
+         */
+        public long getLastUpdateTimeSinceBootMillis() {
+            return mLastUpdateTimeSinceBootMillis;
+        }
     }
 
     /**
@@ -2019,7 +2520,12 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "RECENT_FAILURE_", value = {
             RECENT_FAILURE_NONE,
-            RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA})
+            RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA,
+            RECENT_FAILURE_MBO_OCE_DISCONNECT,
+            RECENT_FAILURE_REFUSED_TEMPORARILY,
+            RECENT_FAILURE_POOR_CHANNEL_CONDITIONS,
+            RECENT_FAILURE_DISCONNECTION_AP_BUSY
+    })
     public @interface RecentFailureReason {}
 
     /**
@@ -2037,12 +2543,46 @@
     public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
 
     /**
+     * This network recently disconnected as a result of MBO/OCE.
+     * @hide
+     */
+    @SystemApi
+    public static final int RECENT_FAILURE_MBO_OCE_DISCONNECT = 1001;
+
+    /**
+     * Failed to connect because the association is rejected by the AP.
+     * IEEE 802.11 association status code 30.
+     * @hide
+     */
+    @SystemApi
+    public static final int RECENT_FAILURE_REFUSED_TEMPORARILY = 1002;
+
+    /**
+     * Failed to connect because of excess frame loss and/or poor channel conditions.
+     * IEEE 802.11 association status code 34.
+     * @hide
+     */
+    @SystemApi
+    public static final int RECENT_FAILURE_POOR_CHANNEL_CONDITIONS = 1003;
+
+    /**
+     * Disconnected by the AP because the AP can't handle all the associated stations.
+     * IEEE 802.11 disconnection reason code 5.
+     * @hide
+     */
+    @SystemApi
+    public static final int RECENT_FAILURE_DISCONNECTION_AP_BUSY = 1004;
+
+    /**
      * Get the failure reason for the most recent connection attempt, or
      * {@link #RECENT_FAILURE_NONE} if there was no failure.
      *
      * Failure reasons include:
      * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}
-     *
+     * {@link #RECENT_FAILURE_MBO_OCE_DISCONNECT}
+     * {@link #RECENT_FAILURE_REFUSED_TEMPORARILY}
+     * {@link #RECENT_FAILURE_POOR_CHANNEL_CONDITIONS}
+     * {@link #RECENT_FAILURE_DISCONNECTION_AP_BUSY}
      * @hide
      */
     @RecentFailureReason
@@ -2103,6 +2643,9 @@
         ephemeral = false;
         osu = false;
         trusted = true; // Networks are considered trusted by default.
+        oemPaid = false;
+        oemPrivate = false;
+        carrierMerged = false;
         fromWifiNetworkSuggestion = false;
         fromWifiNetworkSpecifier = false;
         meteredHint = false;
@@ -2150,12 +2693,11 @@
      */
     @UnsupportedAppUsage
     public boolean isEnterprise() {
-        return (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
-                || allowedKeyManagement.get(KeyMgmt.IEEE8021X)
-                || allowedKeyManagement.get(KeyMgmt.SUITE_B_192)
-                || allowedKeyManagement.get(KeyMgmt.WAPI_CERT))
+        boolean hasEnterpriseSecurityType = mSecurityParamsList.stream()
+                .anyMatch(params -> params.isEnterpriseSecurityType());
+        return (hasEnterpriseSecurityType
                 && enterpriseConfig != null
-                && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
+                && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE);
     }
 
     private static String logTimeOfDay(long millis) {
@@ -2208,9 +2750,13 @@
         }
         if (mNetworkSelectionStatus.getConnectChoice() != null) {
             sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
+            sbuf.append(" connect choice rssi: ")
+                    .append(mNetworkSelectionStatus.getConnectChoiceRssi());
         }
         sbuf.append(" hasEverConnected: ")
                 .append(mNetworkSelectionStatus.hasEverConnected()).append("\n");
+        sbuf.append(" hasNeverDetectedCaptivePortal: ")
+                .append(mNetworkSelectionStatus.hasNeverDetectedCaptivePortal()).append("\n");
 
         if (this.numAssociation > 0) {
             sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
@@ -2223,13 +2769,16 @@
         if (this.ephemeral) sbuf.append(" ephemeral");
         if (this.osu) sbuf.append(" osu");
         if (this.trusted) sbuf.append(" trusted");
+        if (this.oemPaid) sbuf.append(" oemPaid");
+        if (this.oemPrivate) sbuf.append(" oemPrivate");
+        if (this.carrierMerged) sbuf.append(" carrierMerged");
         if (this.fromWifiNetworkSuggestion) sbuf.append(" fromWifiNetworkSuggestion");
         if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier");
         if (this.meteredHint) sbuf.append(" meteredHint");
         if (this.useExternalScores) sbuf.append(" useExternalScores");
-        if (this.validatedInternetAccess || this.ephemeral || this.trusted
-                || this.fromWifiNetworkSuggestion || this.fromWifiNetworkSpecifier
-                || this.meteredHint || this.useExternalScores) {
+        if (this.validatedInternetAccess || this.ephemeral || this.trusted || this.oemPaid
+                || this.oemPrivate || this.carrierMerged || this.fromWifiNetworkSuggestion
+                || this.fromWifiNetworkSpecifier || this.meteredHint || this.useExternalScores) {
             sbuf.append("\n");
         }
         if (this.meteredOverride != METERED_OVERRIDE_NONE) {
@@ -2240,6 +2789,9 @@
         sbuf.append(" randomizedMacExpirationTimeMs: ")
                 .append(randomizedMacExpirationTimeMs == 0 ? "<none>"
                         : logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
+        sbuf.append(" randomizedMacLastModifiedTimeMs: ")
+                .append(randomizedMacLastModifiedTimeMs == 0 ? "<none>"
+                        : logTimeOfDay(randomizedMacLastModifiedTimeMs)).append("\n");
         sbuf.append(" KeyMgmt:");
         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
             if (this.allowedKeyManagement.get(k)) {
@@ -2327,6 +2879,10 @@
             sbuf.append('*');
         }
 
+        sbuf.append("\nSecurityParams List:\n");
+        mSecurityParamsList.stream()
+                .forEach(params -> sbuf.append(params.toString()));
+
         sbuf.append("\nEnterprise config:\n");
         sbuf.append(enterpriseConfig);
 
@@ -2373,7 +2929,8 @@
             }
         }
         sbuf.append("recentFailure: ").append("Association Rejection code: ")
-                .append(recentFailure.getAssociationStatus()).append("\n");
+                .append(recentFailure.getAssociationStatus()).append(", last update time: ")
+                .append(recentFailure.getLastUpdateTimeSinceBootMillis()).append("\n");
         return sbuf.toString();
     }
 
@@ -2491,7 +3048,18 @@
     @KeyMgmt.KeyMgmtScheme
     public int getAuthType() {
         if (allowedKeyManagement.cardinality() > 1) {
-            throw new IllegalStateException("More than one auth type set");
+            if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
+                if (allowedKeyManagement.cardinality() == 2
+                        && allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+                    return KeyMgmt.WPA_EAP;
+                }
+                if (allowedKeyManagement.cardinality() == 3
+                        && allowedKeyManagement.get(KeyMgmt.IEEE8021X)
+                        && allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+                    return KeyMgmt.SUITE_B_192;
+                }
+            }
+            throw new IllegalStateException("Invalid auth type set: " + allowedKeyManagement);
         }
         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
             return KeyMgmt.WPA_PSK;
@@ -2536,6 +3104,26 @@
         return key;
     }
 
+    /**
+     * Get a unique key which represent this Wi-Fi network. If two profiles are for
+     * the same Wi-Fi network, but from different provider, they would have the same key.
+     * @hide
+     */
+    public String getNetworkKey() {
+        // Passpoint ephemeral networks have their unique identifier set. Return it as is to be
+        // able to match internally.
+        if (mPasspointUniqueId != null) {
+            return mPasspointUniqueId;
+        }
+
+        String key = SSID + getDefaultSecurityType();
+        if (!shared) {
+            key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
+        }
+
+        return key;
+    }
+
     /** @hide
      *  return the SSID + security type in String format.
      */
@@ -2743,6 +3331,7 @@
             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
             allowedGroupManagementCiphers = (BitSet) source.allowedGroupManagementCiphers.clone();
             allowedSuiteBCiphers    = (BitSet) source.allowedSuiteBCiphers.clone();
+            mSecurityParamsList = new ArrayList(source.mSecurityParamsList);
             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
 
             defaultGwMacAddress = source.defaultGwMacAddress;
@@ -2759,6 +3348,9 @@
             ephemeral = source.ephemeral;
             osu = source.osu;
             trusted = source.trusted;
+            oemPaid = source.oemPaid;
+            oemPrivate = source.oemPrivate;
+            carrierMerged = source.carrierMerged;
             fromWifiNetworkSuggestion = source.fromWifiNetworkSuggestion;
             fromWifiNetworkSpecifier = source.fromWifiNetworkSpecifier;
             meteredHint = source.meteredHint;
@@ -2781,13 +3373,16 @@
             numNoInternetAccessReports = source.numNoInternetAccessReports;
             noInternetAccessExpected = source.noInternetAccessExpected;
             shared = source.shared;
-            recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
+            recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus(),
+                    source.recentFailure.getLastUpdateTimeSinceBootMillis());
             mRandomizedMacAddress = source.mRandomizedMacAddress;
             macRandomizationSetting = source.macRandomizationSetting;
             randomizedMacExpirationTimeMs = source.randomizedMacExpirationTimeMs;
+            randomizedMacLastModifiedTimeMs = source.randomizedMacLastModifiedTimeMs;
             requirePmf = source.requirePmf;
             updateIdentifier = source.updateIdentifier;
             carrierId = source.carrierId;
+            subscriptionId = source.subscriptionId;
             mPasspointUniqueId = source.mPasspointUniqueId;
         }
     }
@@ -2827,6 +3422,10 @@
         writeBitSet(dest, allowedGroupManagementCiphers);
         writeBitSet(dest, allowedSuiteBCiphers);
 
+        dest.writeInt(mSecurityParamsList.size());
+        mSecurityParamsList.stream()
+                .forEach(params -> params.writeToParcel(dest, flags));
+
         dest.writeParcelable(enterpriseConfig, flags);
 
         dest.writeParcelable(mIpConfiguration, flags);
@@ -2836,6 +3435,9 @@
         dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
         dest.writeInt(ephemeral ? 1 : 0);
         dest.writeInt(trusted ? 1 : 0);
+        dest.writeInt(oemPaid ? 1 : 0);
+        dest.writeInt(oemPrivate ? 1 : 0);
+        dest.writeInt(carrierMerged ? 1 : 0);
         dest.writeInt(fromWifiNetworkSuggestion ? 1 : 0);
         dest.writeInt(fromWifiNetworkSpecifier ? 1 : 0);
         dest.writeInt(meteredHint ? 1 : 0);
@@ -2855,12 +3457,15 @@
         dest.writeInt(shared ? 1 : 0);
         dest.writeString(mPasspointManagementObjectTree);
         dest.writeInt(recentFailure.getAssociationStatus());
+        dest.writeLong(recentFailure.getLastUpdateTimeSinceBootMillis());
         dest.writeParcelable(mRandomizedMacAddress, flags);
         dest.writeInt(macRandomizationSetting);
         dest.writeInt(osu ? 1 : 0);
         dest.writeLong(randomizedMacExpirationTimeMs);
+        dest.writeLong(randomizedMacLastModifiedTimeMs);
         dest.writeInt(carrierId);
         dest.writeString(mPasspointUniqueId);
+        dest.writeInt(subscriptionId);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -2902,6 +3507,11 @@
                 config.allowedGroupManagementCiphers = readBitSet(in);
                 config.allowedSuiteBCiphers   = readBitSet(in);
 
+                int numSecurityParams = in.readInt();
+                for (int i = 0; i < numSecurityParams; i++) {
+                    config.mSecurityParamsList.add(SecurityParams.createFromParcel(in));
+                }
+
                 config.enterpriseConfig = in.readParcelable(null);
                 config.setIpConfiguration(in.readParcelable(null));
                 config.dhcpServer = in.readString();
@@ -2910,6 +3520,9 @@
                 config.isLegacyPasspointConfig = in.readInt() != 0;
                 config.ephemeral = in.readInt() != 0;
                 config.trusted = in.readInt() != 0;
+                config.oemPaid = in.readInt() != 0;
+                config.oemPrivate = in.readInt() != 0;
+                config.carrierMerged = in.readInt() != 0;
                 config.fromWifiNetworkSuggestion =  in.readInt() != 0;
                 config.fromWifiNetworkSpecifier =  in.readInt() != 0;
                 config.meteredHint = in.readInt() != 0;
@@ -2928,13 +3541,15 @@
                 config.noInternetAccessExpected = in.readInt() != 0;
                 config.shared = in.readInt() != 0;
                 config.mPasspointManagementObjectTree = in.readString();
-                config.recentFailure.setAssociationStatus(in.readInt());
+                config.recentFailure.setAssociationStatus(in.readInt(), in.readLong());
                 config.mRandomizedMacAddress = in.readParcelable(null);
                 config.macRandomizationSetting = in.readInt();
                 config.osu = in.readInt() != 0;
                 config.randomizedMacExpirationTimeMs = in.readLong();
+                config.randomizedMacLastModifiedTimeMs = in.readLong();
                 config.carrierId = in.readInt();
                 config.mPasspointUniqueId = in.readString();
+                config.subscriptionId = in.readInt();
                 return config;
             }
 
@@ -2979,9 +3594,66 @@
      * @hide
      */
     public boolean needsPreSharedKey() {
-        return allowedKeyManagement.get(KeyMgmt.WPA_PSK)
-                || allowedKeyManagement.get(KeyMgmt.SAE)
-                || allowedKeyManagement.get(KeyMgmt.WAPI_PSK);
+        return mSecurityParamsList.stream()
+                .anyMatch(params -> params.isSecurityType(SECURITY_TYPE_PSK)
+                        || params.isSecurityType(SECURITY_TYPE_SAE)
+                        || params.isSecurityType(SECURITY_TYPE_WAPI_PSK));
+    }
+
+    /**
+     * Get a unique key which represent this Wi-Fi configuration profile. If two profiles are for
+     * the same Wi-Fi network, but from different providers (apps, carriers, or data subscriptions),
+     * they would have different keys.
+     * @return a unique key which represent this profile.
+     * @hide
+     */
+    @SystemApi
+    @NonNull public String getProfileKey() {
+        if (mPasspointUniqueId != null) {
+            return mPasspointUniqueId;
+        }
+
+        String key = SSID + getDefaultSecurityType();
+        if (!shared) {
+            key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
+        }
+        if (fromWifiNetworkSuggestion) {
+            key += "_" + creatorName + "-" + carrierId + "-" + subscriptionId;
+        }
+
+        return key;
+    }
+
+    /**
+     * Get the default security type string.
+     * @hide
+     */
+    public String getDefaultSecurityType() {
+        String key;
+        if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+            key = KeyMgmt.strings[KeyMgmt.WPA_PSK];
+        } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
+                || allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+            key = KeyMgmt.strings[KeyMgmt.WPA_EAP];
+        } else if (wepTxKeyIndex >= 0 && wepTxKeyIndex < wepKeys.length
+                && wepKeys[wepTxKeyIndex] != null) {
+            key = "WEP";
+        } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
+            key = KeyMgmt.strings[KeyMgmt.OWE];
+        } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
+            key = KeyMgmt.strings[KeyMgmt.SAE];
+        } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+            key = KeyMgmt.strings[KeyMgmt.SUITE_B_192];
+        } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
+            key = KeyMgmt.strings[KeyMgmt.WAPI_PSK];
+        } else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
+            key = KeyMgmt.strings[KeyMgmt.WAPI_CERT];
+        } else if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
+            key = KeyMgmt.strings[KeyMgmt.OSEN];
+        } else {
+            key = KeyMgmt.strings[KeyMgmt.NONE];
+        }
+        return key;
     }
 
 }
diff --git a/framework/java/android/net/wifi/WifiEnterpriseConfig.java b/framework/java/android/net/wifi/WifiEnterpriseConfig.java
index 90edc45..e127ea9 100644
--- a/framework/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/framework/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -1335,6 +1335,16 @@
     }
 
     /**
+     * Initialize the value of the app installed device key and cert flag.
+     *
+     * @param isAppInstalledDeviceKeyAndCert true or false
+     * @hide
+     */
+    public void initIsAppInstalledDeviceKeyAndCert(boolean isAppInstalledDeviceKeyAndCert) {
+        mIsAppInstalledDeviceKeyAndCert = isAppInstalledDeviceKeyAndCert;
+    }
+
+    /**
      * Check if CA certificate was installed by an app, or manually (not by an app). If true,
      * CA certificate will be removed from key storage when this network is removed. If not,
      * then certificates and keys remain persistent until the user manually removes them.
@@ -1348,6 +1358,16 @@
     }
 
     /**
+     * Initialize the value of the app installed root CA cert flag.
+     *
+     * @param isAppInstalledCaCert true or false
+     * @hide
+     */
+    public void initIsAppInstalledCaCert(boolean isAppInstalledCaCert) {
+        mIsAppInstalledCaCert = isAppInstalledCaCert;
+    }
+
+    /**
      * Set the OCSP type.
      * @param ocsp is one of {@link ##OCSP_NONE}, {@link #OCSP_REQUEST_CERT_STATUS},
      *                   {@link #OCSP_REQUIRE_CERT_STATUS} or
diff --git a/framework/java/android/net/wifi/WifiInfo.java b/framework/java/android/net/wifi/WifiInfo.java
index 5388367..6bd1ce5 100644
--- a/framework/java/android/net/wifi/WifiInfo.java
+++ b/framework/java/android/net/wifi/WifiInfo.java
@@ -25,8 +25,10 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 
+import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.Inet4AddressUtils;
 
 import java.net.Inet4Address;
@@ -159,6 +161,21 @@
     private boolean mTrusted;
 
     /**
+     * Whether the network is oem paid or not.
+     */
+    private boolean mOemPaid;
+
+    /**
+     * Whether the network is oem private or not.
+     */
+    private boolean mOemPrivate;
+
+    /**
+     * Whether the network is a carrier merged network.
+     */
+    private boolean mCarrierMerged;
+
+    /**
      * OSU (Online Sign Up) AP for Passpoint R2.
      */
     private boolean mOsuAp;
@@ -180,6 +197,11 @@
     private String mRequestingPackageName;
 
     /**
+     * Identify which Telephony subscription provides this network.
+     */
+    private int mSubscriptionId;
+
+    /**
      * Running total count of lost (not ACKed) transmitted unicast data packets.
      * @hide
      */
@@ -305,6 +327,7 @@
         mRssi = INVALID_RSSI;
         mLinkSpeed = LINK_SPEED_UNKNOWN;
         mFrequency = -1;
+        mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     }
 
     /** @hide */
@@ -322,11 +345,16 @@
         setFrequency(-1);
         setMeteredHint(false);
         setEphemeral(false);
+        setTrusted(false);
+        setOemPaid(false);
+        setOemPrivate(false);
+        setCarrierMerged(false);
         setOsuAp(false);
         setRequestingPackageName(null);
         setFQDN(null);
         setProviderFriendlyName(null);
         setPasspointUniqueId(null);
+        setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         txBad = 0;
         txSuccess = 0;
         rxSuccess = 0;
@@ -358,11 +386,15 @@
             mMeteredHint = source.mMeteredHint;
             mEphemeral = source.mEphemeral;
             mTrusted = source.mTrusted;
+            mOemPaid = source.mOemPaid;
+            mOemPrivate = source.mOemPrivate;
+            mCarrierMerged = source.mCarrierMerged;
             mRequestingPackageName =
                     source.mRequestingPackageName;
             mOsuAp = source.mOsuAp;
             mFqdn = source.mFqdn;
             mProviderFriendlyName = source.mProviderFriendlyName;
+            mSubscriptionId = source.mSubscriptionId;
             txBad = source.txBad;
             txRetries = source.txRetries;
             txSuccess = source.txSuccess;
@@ -716,12 +748,74 @@
         mTrusted = trusted;
     }
 
-    /** {@hide} */
+    /**
+     * Returns true if the current Wifi network is a trusted network, false otherwise.
+     * @see WifiNetworkSuggestion.Builder#setUntrusted(boolean).
+     * {@hide}
+     */
+    @SystemApi
     public boolean isTrusted() {
         return mTrusted;
     }
 
     /** {@hide} */
+    public void setOemPaid(boolean oemPaid) {
+        mOemPaid = oemPaid;
+    }
+
+    /**
+     * Returns true if the current Wifi network is an oem paid network, false otherwise.
+     * @see WifiNetworkSuggestion.Builder#setOemPaid(boolean).
+     * {@hide}
+     */
+    @SystemApi
+    public boolean isOemPaid() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mOemPaid;
+    }
+
+    /** {@hide} */
+    public void setOemPrivate(boolean oemPrivate) {
+        mOemPrivate = oemPrivate;
+    }
+
+    /**
+     * Returns true if the current Wifi network is an oem private network, false otherwise.
+     * @see WifiNetworkSuggestion.Builder#setOemPrivate(boolean).
+     * {@hide}
+     */
+    @SystemApi
+    public boolean isOemPrivate() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mOemPrivate;
+    }
+
+    /**
+     * {@hide}
+     */
+    public void setCarrierMerged(boolean carrierMerged) {
+        mCarrierMerged = carrierMerged;
+    }
+
+    /**
+     * Returns true if the current Wifi network is a carrier merged network, false otherwise.
+     * @see WifiNetworkSuggestion.Builder#setCarrierMerged(boolean).
+     * {@hide}
+     */
+    @SystemApi
+    public boolean isCarrierMerged() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mCarrierMerged;
+    }
+
+
+    /** {@hide} */
     public void setOsuAp(boolean osuAp) {
         mOsuAp = osuAp;
     }
@@ -789,6 +883,28 @@
         return mRequestingPackageName;
     }
 
+    /** {@hide} */
+    public void setSubscriptionId(int subId) {
+        mSubscriptionId = subId;
+    }
+
+    /**
+     * If this network is provisioned by a carrier, returns subscription Id corresponding to the
+     * associated SIM on the device. If this network is not provisioned by a carrier, returns
+     * {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}
+     *
+     * @see WifiNetworkSuggestion.Builder#setSubscriptionId(int)
+     * @see android.telephony.SubscriptionInfo#getSubscriptionId()
+     * {@hide}
+     */
+    @SystemApi
+    public int getSubscriptionId() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mSubscriptionId;
+    }
+
 
     /** @hide */
     @UnsupportedAppUsage
@@ -958,6 +1074,9 @@
         dest.writeInt(mMeteredHint ? 1 : 0);
         dest.writeInt(mEphemeral ? 1 : 0);
         dest.writeInt(mTrusted ? 1 : 0);
+        dest.writeInt(mOemPaid ? 1 : 0);
+        dest.writeInt(mOemPrivate ? 1 : 0);
+        dest.writeInt(mCarrierMerged ? 1 : 0);
         dest.writeInt(score);
         dest.writeLong(txSuccess);
         dest.writeDouble(mSuccessfulTxPacketsPerSecond);
@@ -976,6 +1095,7 @@
         dest.writeInt(mMaxSupportedTxLinkSpeed);
         dest.writeInt(mMaxSupportedRxLinkSpeed);
         dest.writeString(mPasspointUniqueId);
+        dest.writeInt(mSubscriptionId);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -1003,6 +1123,9 @@
                 info.mMeteredHint = in.readInt() != 0;
                 info.mEphemeral = in.readInt() != 0;
                 info.mTrusted = in.readInt() != 0;
+                info.mOemPaid = in.readInt() != 0;
+                info.mOemPrivate = in.readInt() != 0;
+                info.mCarrierMerged = in.readInt() != 0;
                 info.score = in.readInt();
                 info.txSuccess = in.readLong();
                 info.mSuccessfulTxPacketsPerSecond = in.readDouble();
@@ -1021,6 +1144,7 @@
                 info.mMaxSupportedTxLinkSpeed = in.readInt();
                 info.mMaxSupportedRxLinkSpeed = in.readInt();
                 info.mPasspointUniqueId = in.readString();
+                info.mSubscriptionId = in.readInt();
                 return info;
             }
 
diff --git a/framework/java/android/net/wifi/WifiManager.java b/framework/java/android/net/wifi/WifiManager.java
index ccf8a80..5618ee8 100644
--- a/framework/java/android/net/wifi/WifiManager.java
+++ b/framework/java/android/net/wifi/WifiManager.java
@@ -34,7 +34,6 @@
 import android.app.ActivityManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.pm.ParceledListSlice;
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.MacAddress;
@@ -53,6 +52,8 @@
 import android.os.RemoteException;
 import android.os.WorkSource;
 import android.os.connectivity.WifiActivityEnergyInfo;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.CloseGuard;
 import android.util.Log;
@@ -61,6 +62,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.ParceledListSlice;
+import com.android.modules.utils.build.SdkLevel;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -70,6 +73,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -263,6 +267,44 @@
     public @interface SuggestionConnectionStatusCode {}
 
     /**
+     * Status code if suggestion approval status is unknown, an App which hasn't made any
+     * suggestions will get this code.
+     */
+    public static final int STATUS_SUGGESTION_APPROVAL_UNKNOWN = 0;
+
+    /**
+     * Status code if the calling app is still pending user approval for suggestions.
+     */
+    public static final int STATUS_SUGGESTION_APPROVAL_PENDING = 1;
+
+    /**
+     * Status code if the calling app got the user approval for suggestions.
+     */
+    public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER = 2;
+
+    /**
+     * Status code if the calling app suggestions were rejected by the user.
+     */
+    public static final int STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER = 3;
+
+    /**
+     * Status code if the calling app was approved by virtue of being a carrier privileged app.
+     * @see TelephonyManager#hasCarrierPrivileges().
+     */
+    public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE = 4;
+
+    /** @hide */
+    @IntDef(prefix = {"STATUS_SUGGESTION_APPROVAL_"},
+            value = {STATUS_SUGGESTION_APPROVAL_UNKNOWN,
+                    STATUS_SUGGESTION_APPROVAL_PENDING,
+                    STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER,
+                    STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER,
+                    STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SuggestionUserApprovalStatus {}
+
+    /**
      * Broadcast intent action indicating whether Wi-Fi scanning is currently available.
      * Available extras:
      * - {@link #EXTRA_SCAN_AVAILABLE}
@@ -931,9 +973,11 @@
      * This can be as a result of adding/updating/deleting a network.
      * <br />
      * {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
-     * {@link #EXTRA_WIFI_CONFIGURATION} is never set starting in Android 11.
+     * {@link #EXTRA_WIFI_CONFIGURATION} is never set beginning in
+     * {@link android.os.Build.VERSION_CODES#R}.
      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
-     * its value is always true, even if only a single network changed.
+     * its value is always true beginning in {@link android.os.Build.VERSION_CODES#R}, even if only
+     * a single network changed.
      * <br />
      * The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
      * required to receive this broadcast.
@@ -947,17 +991,22 @@
      * The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
      * broadcast is sent.
-     * Note: this extra is never set starting in Android 11.
+     * @deprecated This extra is never set beginning in {@link android.os.Build.VERSION_CODES#R},
+     * regardless of the target SDK version. Use {@link #getConfiguredNetworks} to get the full list
+     * of configured networks.
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
     /**
      * Multiple network configurations have changed.
      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
-     * Note: this extra is always true starting in Android 11.
+     * @deprecated This extra's value is always true beginning in
+     * {@link android.os.Build.VERSION_CODES#R}, regardless of the target SDK version.
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     /**
@@ -1053,9 +1102,6 @@
 
     /**
      * Broadcast intent action indicating that the link configuration changed on wifi.
-     * <br />Included Extras:
-     * <br />{@link #EXTRA_LINK_PROPERTIES}: may not be set starting in Android 11. Check for
-     * <br /> null before reading its value.
      * <br /> No permissions are required to listen to this broadcast.
      * @hide
      */
@@ -1072,11 +1118,11 @@
      *
      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
      *
-     * Note: this extra may not be set starting in Android 11. Check for null before reading its
-     * value.
+     * @deprecated this extra is no longer populated.
      *
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
 
@@ -1444,7 +1490,7 @@
                             new ArrayList<>(results.keySet()));
             for (WifiConfiguration configuration : wifiConfigurations) {
                 Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
-                        results.get(configuration.getKey());
+                        results.get(configuration.getProfileKey());
                 if (scanResultsPerNetworkType != null) {
                     configs.add(Pair.create(configuration, scanResultsPerNetworkType));
                 }
@@ -2005,6 +2051,26 @@
     }
 
     /**
+     * Get the Suggestion approval status of the calling app. When an app makes suggestions using
+     * the {@link #addNetworkSuggestions(List)} API they may trigger a user approval flow. This API
+     * provides the current approval status.
+     *
+     * @return Status code for the user approval. One of the STATUS_SUGGESTION_APPROVAL_ values.
+     * @throws {@link SecurityException} if the caller is missing required permissions.
+     */
+    @RequiresPermission(ACCESS_WIFI_STATE)
+    public @SuggestionUserApprovalStatus int getNetworkSuggestionUserApprovalStatus() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mService.getNetworkSuggestionUserApprovalStatus(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
      * Add or update a Passpoint configuration.  The configuration provides a credential
      * for connecting to Passpoint networks that are operated by the Passpoint
      * service provider specified in the configuration.
@@ -2123,22 +2189,6 @@
     }
 
     /**
-     * Deauthenticate and set the re-authentication hold off time for the current network
-     * @param holdoff hold off time in milliseconds
-     * @param ess set if the hold off pertains to an ESS rather than a BSS
-     * @hide
-     *
-     * TODO (140167680): This needs to be removed, the implementation is empty!
-     */
-    public void deauthenticateNetwork(long holdoff, boolean ess) {
-        try {
-            mService.deauthenticateNetwork(holdoff, ess);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Remove the specified network from the list of configured networks.
      * This may result in the asynchronous delivery of state change
      * events.
@@ -2427,6 +2477,8 @@
     public static final long WIFI_FEATURE_OCE              = 0x1000000000L; // OCE Support
     /** @hide */
     public static final long WIFI_FEATURE_WAPI             = 0x2000000000L; // WAPI
+    /** @hide */
+    public static final long WIFI_FEATURE_INFRA_60G        = 0x4000000000L; // 60 GHz Band Support
 
     /** @hide */
     public static final long WIFI_FEATURE_FILS_SHA256     = 0x4000000000L; // FILS-SHA256
@@ -2434,6 +2486,15 @@
     /** @hide */
     public static final long WIFI_FEATURE_FILS_SHA384     = 0x8000000000L; // FILS-SHA384
 
+    /** @hide */
+    public static final long WIFI_FEATURE_SAE_PK          = 0x10000000000L; // SAE-PK
+
+    /** @hide */
+    public static final long WIFI_FEATURE_STA_BRIDGED_AP       = 0x20000000000L; // STA + Bridged AP
+
+    /** @hide */
+    public static final long WIFI_FEATURE_BRIDGED_AP           = 0x40000000000L; // Bridged AP
+
     private long getSupportedFeatures() {
         try {
             return mService.getSupportedFeatures();
@@ -2497,6 +2558,18 @@
     }
 
     /**
+     * Query whether the device supports 2 or more concurrent stations (STA) or not.
+     *
+     * @return true if this device supports multiple STA concurrency, false otherwise.
+     */
+    public boolean isMultiStaConcurrencySupported() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
+    }
+
+    /**
      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
      * {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
@@ -2529,14 +2602,6 @@
     }
 
     /**
-     * @return true if this adapter supports multiple simultaneous connections
-     * @hide
-     */
-    public boolean isAdditionalStaSupported() {
-        return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
-    }
-
-    /**
      * @return true if this adapter supports Tunnel Directed Link Setup
      */
     public boolean isTdlsSupported() {
@@ -2589,6 +2654,21 @@
     }
 
     /**
+     * Check if the chipset supports the 60GHz frequency band.
+     *
+     * @return {@code true} if supported, {@code false} otherwise.
+     * @hide
+     */
+    @SystemApi
+    public boolean is60GHzBandSupported() {
+        try {
+            return mService.is60GHzBandSupported();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Check if the chipset supports 6GHz band.
      * @return {@code true} if supported, {@code false} otherwise.
      */
@@ -2615,6 +2695,40 @@
     }
 
     /**
+     * Query whether the device supports Station (STA) + Bridged access point (AP)
+     * concurrency or not.
+     *
+     * The bridged AP support means that the device supports AP + AP concurrency with the 2 APs
+     * bridged together.
+     *
+     * See {@link SoftApConfiguration.Builder#setBands(int[])}
+     * or {@link SoftApConfiguration.Builder#setChannels(SparseIntArray)} to configure bridged AP
+     * when the bridged AP supported.
+     *
+     * @return true if this device supports STA + bridged AP concurrency, false otherwise.
+     */
+    public boolean isStaBridgedApConcurrencySupported() {
+        return isFeatureSupported(WIFI_FEATURE_STA_BRIDGED_AP);
+    }
+
+    /**
+     * Query whether the device supports Bridged Access point (AP) concurrency or not.
+     *
+     * The bridged AP support means that the device supports AP + AP concurrency with the 2 APs
+     * bridged together.
+     *
+     * See {@link SoftApConfiguration.Builder#setBands(int[])}
+     * or {@link SoftApConfiguration.Builder#setChannels(SparseIntArray)} to configure bridged AP
+     * when the bridged AP supported.
+     *
+     * @return true if this device supports bridged AP concurrency, false otherwise.
+     */
+    public boolean isBridgedApConcurrencySupported() {
+        return isFeatureSupported(WIFI_FEATURE_BRIDGED_AP);
+    }
+
+
+    /**
      * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
      * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
      *
@@ -2822,7 +2936,7 @@
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void setScanAlwaysAvailable(boolean isAvailable) {
         try {
-            mService.setScanAlwaysAvailable(isAvailable);
+            mService.setScanAlwaysAvailable(isAvailable, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2927,6 +3041,37 @@
     }
 
     /**
+     * Restart the Wi-Fi subsystem.
+     *
+     * Restarts the Wi-Fi subsystem - effectively disabling it and re-enabling it. All existing
+     * Access Point (AP) associations are torn down, all Soft APs are disabled, Wi-Fi Direct and
+     * Wi-Fi Aware are disabled.
+     *
+     * The state of the system after restart is not guaranteed to match its state before the API is
+     * called - for instance the device may associate to a different Access Point (AP), and tethered
+     * hotspots may or may not be restored.
+     *
+     * @param reason If non-null, requests a bug report and attaches the reason string to it. A bug
+     *               report may still not be generated based on framework criteria - for instance,
+     *               build type or throttling. The WiFi subsystem is restarted whether or not a bug
+     *               report is requested or generated.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_AIRPLANE_MODE)
+    public void restartWifiSubsystem(@Nullable String reason) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            mService.restartWifiSubsystem(reason);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets the Wi-Fi enabled state.
      * @return One of {@link #WIFI_STATE_DISABLED},
      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
@@ -3038,6 +3183,251 @@
         }
     }
 
+    /* Wi-Fi/Cellular Coex */
+
+    /**
+     * Mandatory coex restriction flag for Wi-Fi Direct.
+     *
+     * @see #setCoexUnsafeChannels(Set, int)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int COEX_RESTRICTION_WIFI_DIRECT = 0x1 << 0;
+
+    /**
+     * Mandatory coex restriction flag for SoftAP
+     *
+     * @see #setCoexUnsafeChannels(Set, int)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int COEX_RESTRICTION_SOFTAP = 0x1 << 1;
+
+    /**
+     * Mandatory coex restriction flag for Wi-Fi Aware.
+     *
+     * @see #setCoexUnsafeChannels(Set, int)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int COEX_RESTRICTION_WIFI_AWARE = 0x1 << 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = {"COEX_RESTRICTION_"}, value = {
+            COEX_RESTRICTION_WIFI_DIRECT,
+            COEX_RESTRICTION_SOFTAP,
+            COEX_RESTRICTION_WIFI_AWARE
+    })
+    public @interface CoexRestriction {}
+
+    /**
+     * @return {@code true} if the default coex algorithm is enabled. {@code false} otherwise.
+     *
+     * @hide
+     */
+    public boolean isDefaultCoexAlgorithmEnabled() {
+        try {
+            return mService.isDefaultCoexAlgorithmEnabled();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Specify the set of {@link CoexUnsafeChannel} to propagate through the framework for
+     * Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay
+     * (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing.
+     *
+     * @param unsafeChannels Set of {@link CoexUnsafeChannel} to avoid.
+     * @param restrictions Bitmap of {@link CoexRestriction} specifying the mandatory restricted
+     *                     uses of the specified channels. If any restrictions are set, then the
+     *                     supplied CoexUnsafeChannels will be completely avoided for the
+     *                     specified modes, rather than be avoided with best effort.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS)
+    public void setCoexUnsafeChannels(@NonNull Set<CoexUnsafeChannel> unsafeChannels,
+            int restrictions) {
+        if (unsafeChannels == null) {
+            throw new IllegalArgumentException("unsafeChannels must not be null");
+        }
+        try {
+            mService.setCoexUnsafeChannels(new ArrayList<>(unsafeChannels), restrictions);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the set of current {@link CoexUnsafeChannel} being used for Wi-Fi/Cellular coex
+     * channel avoidance.
+     *
+     * This returns the set calculated by the default algorithm if
+     * config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, returns the set supplied
+     * in {@link #setCoexUnsafeChannels(Set, int)}.
+     *
+     * If any {@link CoexRestriction} flags are set in {@link #getCoexRestrictions()}, then the
+     * CoexUnsafeChannels should be totally avoided (i.e. not best effort) for the Wi-Fi modes
+     * specified by the flags.
+     *
+     * @return Set of current CoexUnsafeChannels.
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+    public Set<CoexUnsafeChannel> getCoexUnsafeChannels() {
+        try {
+            return new HashSet<>(mService.getCoexUnsafeChannels());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the current coex restrictions being used for Wi-Fi/Cellular coex
+     * channel avoidance.
+     *
+     * This returns the restrictions calculated by the default algorithm if
+     * config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, returns the value supplied
+     * in {@link #setCoexUnsafeChannels(Set, int)}.
+     *
+     * @return int containing a bitwise-OR combination of {@link CoexRestriction}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+    public int getCoexRestrictions() {
+        try {
+            return mService.getCoexRestrictions();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Registers a CoexCallback to listen on the current CoexUnsafeChannels and restrictions being
+     * used for Wi-Fi/cellular coex channel avoidance.
+     * @param executor Executor to execute listener callback on
+     * @param callback CoexCallback to register
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+    public void registerCoexCallback(
+            @NonNull @CallbackExecutor Executor executor, @NonNull CoexCallback callback) {
+        if (executor == null) throw new IllegalArgumentException("executor must not be null");
+        if (callback == null) throw new IllegalArgumentException("callback must not be null");
+        CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
+        proxy.initProxy(executor, callback);
+        try {
+            mService.registerCoexCallback(proxy);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unregisters a CoexCallback from listening on the current CoexUnsafeChannels and restrictions
+     * being used for Wi-Fi/cellular coex channel avoidance.
+     * @param callback CoexCallback to unregister
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+    public void unregisterCoexCallback(@NonNull CoexCallback callback) {
+        if (callback == null) throw new IllegalArgumentException("callback must not be null");
+        CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
+        try {
+            mService.unregisterCoexCallback(proxy);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } finally {
+            proxy.cleanUpProxy();
+        }
+    }
+
+    /**
+     * Abstract callback class for applications to receive updates about current CoexUnsafeChannels
+     * for Wi-Fi/Cellular coex channel avoidance.
+     *
+     * @hide
+     */
+    @SystemApi
+    public abstract static class CoexCallback {
+        private final CoexCallbackProxy mCoexCallbackProxy;
+
+        public CoexCallback() {
+            mCoexCallbackProxy = new CoexCallbackProxy();
+        }
+
+        /*package*/ @NonNull
+        CoexCallbackProxy getProxy() {
+            return mCoexCallbackProxy;
+        }
+
+        /**
+         * Indicates that the current CoexUnsafeChannels or restrictions have changed.
+         * Clients should call {@link #getCoexUnsafeChannels()} and {@link #getCoexRestrictions()}
+         * to get the updated values.
+         */
+        public abstract void onCoexUnsafeChannelsChanged();
+
+        /**
+         * Callback proxy for CoexCallback objects.
+         */
+        private static class CoexCallbackProxy extends ICoexCallback.Stub {
+            private final Object mLock = new Object();
+            @Nullable @GuardedBy("mLock") private Executor mExecutor;
+            @Nullable @GuardedBy("mLock") private CoexCallback mCallback;
+
+            CoexCallbackProxy() {
+                mExecutor = null;
+                mCallback = null;
+            }
+
+            /*package*/ void initProxy(@NonNull Executor executor,
+                    @NonNull CoexCallback callback) {
+                synchronized (mLock) {
+                    mExecutor = executor;
+                    mCallback = callback;
+                }
+            }
+
+            /*package*/ void cleanUpProxy() {
+                synchronized (mLock) {
+                    mExecutor = null;
+                    mCallback = null;
+                }
+            }
+
+            @Override
+            public void onCoexUnsafeChannelsChanged() {
+                Executor executor;
+                CoexCallback callback;
+                synchronized (mLock) {
+                    executor = mExecutor;
+                    callback = mCallback;
+                }
+                if (executor == null || callback == null) {
+                    return;
+                }
+                Binder.clearCallingIdentity();
+                executor.execute(callback::onCoexUnsafeChannelsChanged);
+            }
+        }
+    }
+
     /**
      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
      * Note that starting Soft AP mode may disable station mode operation if the device does not
@@ -3055,7 +3445,7 @@
     })
     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
         try {
-            return mService.startSoftAp(wifiConfig);
+            return mService.startSoftAp(wifiConfig, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3079,7 +3469,7 @@
     })
     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
         try {
-            return mService.startTetheredHotspot(softApConfig);
+            return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3396,7 +3786,10 @@
      */
     @NonNull
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.OVERRIDE_WIFI_CONFIG
+    })
     public SoftApConfiguration getSoftApConfiguration() {
         try {
             return mService.getSoftApConfiguration();
@@ -3444,7 +3837,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.OVERRIDE_WIFI_CONFIG
+    })
     public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
         try {
             return mService.setSoftApConfiguration(
@@ -3630,9 +4026,34 @@
          */
         default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
 
+
+        /**
+         * Called when the connected clients for a soft AP instance change.
+         *
+         * When the Soft AP is configured in single AP mode, this callback is invoked
+         * with the same {@link SoftApInfo} for all connected clients changes.
+         * When the Soft AP is configured in bridged mode, this callback is invoked with
+         * the corresponding {@link SoftApInfo} for the instance in which the connected clients
+         * changed.
+         *
+         * Use {@link #onConnectedClientsChanged(List<WifiClient>)} if you don't care about
+         * the mapping from SoftApInfo instance to connected clients.
+         *
+         * @param info The {@link SoftApInfo} of the AP.
+         * @param clients The currently connected clients on the AP instance specified by
+         *                {@code info}.
+         */
+        default void onConnectedClientsChanged(@NonNull SoftApInfo info,
+                @NonNull List<WifiClient> clients) {}
+
         /**
          * Called when information of softap changes.
          *
+         * Note: this API is only valid when the Soft AP is configured as a single AP
+         * - not as a bridged AP (2 Soft APs). When the Soft AP is configured as bridged AP
+         * this callback will not be triggered -  use the
+         * {@link #onInfoChanged(List<SoftApInfo>)} callback in bridged AP mode.
+         *
          * @param softApInfo is the softap information. {@link SoftApInfo}
          */
         default void onInfoChanged(@NonNull SoftApInfo softApInfo) {
@@ -3640,6 +4061,28 @@
         }
 
         /**
+         * Called when information of softap changes.
+         *
+         * The number of the information elements in the list depends on Soft AP configuration
+         * and state.
+         * For instance, an empty list will be returned when the Soft AP is disabled.
+         * One information element will be returned in the list when the Soft AP is configured
+         * as a single AP, and two information elements will be returned in the list
+         * when the Soft AP is configured in bridged mode.
+         *
+         * Note: One of the Soft APs may be shut down independently of the other by the framework,
+         * for instance if no devices are connected to it for some duration.
+         * In that case, one information element will be returned in the list in bridged mode.
+         *
+         * See {@link #isBridgedApConcurrencySupported()} for the detail of the bridged AP.
+         *
+         * @param softApInfoList is the list of the softap information elements. {@link SoftApInfo}
+         */
+        default void onInfoChanged(@NonNull List<SoftApInfo> softApInfoList) {
+            // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
+        }
+
+        /**
          * Called when capability of softap changes.
          *
          * @param softApCapability is the softap capability. {@link SoftApCapability}
@@ -3674,6 +4117,16 @@
     private class SoftApCallbackProxy extends ISoftApCallback.Stub {
         private final Executor mExecutor;
         private final SoftApCallback mCallback;
+        private Map<String, List<WifiClient>> mCurrentClients = new HashMap<>();
+        private Map<String, SoftApInfo> mCurrentInfos = new HashMap<>();
+
+        private List<WifiClient> getConnectedClientList(Map<String, List<WifiClient>> clientsMap) {
+            List<WifiClient> connectedClientList = new ArrayList<>();
+            for (List<WifiClient> it : clientsMap.values()) {
+                connectedClientList.addAll(it);
+            }
+            return connectedClientList;
+        }
 
         SoftApCallbackProxy(Executor executor, SoftApCallback callback) {
             mExecutor = executor;
@@ -3694,28 +4147,84 @@
         }
 
         @Override
-        public void onConnectedClientsChanged(List<WifiClient> clients) {
+        public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
+                Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration) {
             if (mVerboseLoggingEnabled) {
-                Log.v(TAG, "SoftApCallbackProxy: onConnectedClientsChanged: clients="
-                        + clients.size() + " clients");
+                Log.v(TAG, "SoftApCallbackProxy: onConnectedClientsOrInfoChanged: clients: "
+                        + clients + ", infos: " + infos + ", isBridged is " + isBridged
+                        + ", isRegistration is " + isRegistration);
             }
 
-            Binder.clearCallingIdentity();
-            mExecutor.execute(() -> {
-                mCallback.onConnectedClientsChanged(clients);
-            });
-        }
-
-        @Override
-        public void onInfoChanged(SoftApInfo softApInfo) {
-            if (mVerboseLoggingEnabled) {
-                Log.v(TAG, "SoftApCallbackProxy: onInfoChange: softApInfo=" + softApInfo);
+            List<SoftApInfo> changedInfoList = new ArrayList<>(infos.values());
+            Map<SoftApInfo, List<WifiClient>> changedInfoClients = new HashMap<>();
+            boolean isInfoChanged = infos.size() != mCurrentInfos.size();
+            for (SoftApInfo info : mCurrentInfos.values()) {
+                String changedInstance = info.getApInstanceIdentifier();
+                if (!changedInfoList.contains(info)) {
+                    isInfoChanged = true;
+                    if (mCurrentClients.getOrDefault(changedInstance,
+                              Collections.emptyList()).size() > 0) {
+                        Log.d(TAG, "SoftApCallbackProxy: info changed on client connected"
+                                + " instance(Shut Down case)");
+                        //Here should notify client changed on old info
+                        changedInfoClients.put(info, Collections.emptyList());
+                    }
+                } else {
+                    // info doesn't change, check client list
+                    List<WifiClient> changedClientList = clients.getOrDefault(
+                            changedInstance, Collections.emptyList());
+                    if (changedClientList.size()
+                            != mCurrentClients
+                            .getOrDefault(changedInstance, Collections.emptyList()).size()) {
+                        // Here should notify client changed on new info(same as old info)
+                        changedInfoClients.put(info, changedClientList);
+                        Log.d(TAG, "SoftApCallbackProxy: client changed on " + info
+                                + " list: " + changedClientList);
+                    }
+                }
             }
 
+            if (!isInfoChanged && changedInfoClients.isEmpty()
+                    && !isRegistration) {
+                Log.v(TAG, "SoftApCallbackProxy: No changed & Not Registration,"
+                        + " don't need to notify the client");
+                return;
+            }
+            mCurrentClients = clients;
+            mCurrentInfos = infos;
             Binder.clearCallingIdentity();
-            mExecutor.execute(() -> {
-                mCallback.onInfoChanged(softApInfo);
-            });
+            // Notify the clients changed first for old info shutdown case
+            for (SoftApInfo changedInfo : changedInfoClients.keySet()) {
+                Log.v(TAG, "send onConnectedClientsChanged, changedInfo is " + changedInfo);
+                mExecutor.execute(() -> {
+                    mCallback.onConnectedClientsChanged(
+                            changedInfo, changedInfoClients.get(changedInfo));
+                });
+            }
+
+            if (isInfoChanged || isRegistration) {
+                if (!isBridged) {
+                    SoftApInfo newInfo = changedInfoList.isEmpty()
+                            ? new SoftApInfo() : changedInfoList.get(0);
+                    Log.v(TAG, "SoftApCallbackProxy: send InfoChanged, newInfo: " + newInfo);
+                    mExecutor.execute(() -> {
+                        mCallback.onInfoChanged(newInfo);
+                    });
+                }
+                Log.v(TAG, "SoftApCallbackProxy: send InfoChanged, changedInfoList: "
+                        + changedInfoList);
+                mExecutor.execute(() -> {
+                    mCallback.onInfoChanged(changedInfoList);
+                });
+            }
+
+            if (isRegistration || !changedInfoClients.isEmpty()) {
+                Log.v(TAG, "SoftApCallbackProxy: send onConnectedClientsChanged(clients): "
+                        + getConnectedClientList(clients));
+                mExecutor.execute(() -> {
+                    mCallback.onConnectedClientsChanged(getConnectedClientList(clients));
+                });
+            }
         }
 
         @Override
@@ -3752,8 +4261,20 @@
      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
      * <li> {@link SoftApCallback#onInfoChanged(SoftApInfo)}</li>
+     * <li> {@link SoftApCallback#onInfoChanged(List<SoftApInfo>)}</li>
      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
      * </ul>
+     *
+     * Use {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)} to know if there are
+     * any clients connected to any of the bridged instances of this AP (if bridged AP is enabled).
+     * Use {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} to know
+     * if there are any clients connected to a specific bridged instance of this AP
+     * (if bridged AP is enabled).
+     *
+     * Note: Caller will receive the callback
+     * {@link SoftApCallback#onConnectedClientsChangedWithApInfo(SoftApInfo, List<WifiClient>)}
+     * on registration when there are clients connected to AP.
+     *
      * These will be dispatched on registration to provide the caller with the current state
      * (and are not an indication of any current change). Note that receiving an immediate
      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
@@ -4148,14 +4669,11 @@
     private void connectInternal(@Nullable WifiConfiguration config, int networkId,
             @Nullable ActionListener listener) {
         ActionListenerProxy listenerProxy = null;
-        Binder binder = null;
         if (listener != null) {
             listenerProxy = new ActionListenerProxy("connect", mLooper, listener);
-            binder = new Binder();
         }
         try {
-            mService.connect(config, networkId, binder, listenerProxy,
-                    listener == null ? 0 : listener.hashCode());
+            mService.connect(config, networkId, listenerProxy);
         } catch (RemoteException e) {
             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
         } catch (SecurityException e) {
@@ -4217,6 +4735,49 @@
     }
 
     /**
+     * Temporarily disable autojoin for all currently visible and provisioned (saved, suggested)
+     * wifi networks except merged carrier networks from the provided subscription ID.
+     *
+     * Disabled networks will get automatically re-enabled when they are out of range for a period
+     * of time, or after the maximum disable duration specified in the framework.
+     *
+     * Calling {@link #stopTemporarilyDisablingAllNonCarrierMergedWifi()} will immediately re-enable
+     * autojoin on all disabled networks.
+     *
+     * @param subscriptionId the subscription ID of the carrier whose merged wifi networks won't be
+     *                       disabled {@link android.telephony.SubscriptionInfo#getSubscriptionId()}
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void startTemporarilyDisablingAllNonCarrierMergedWifi(int subscriptionId) {
+        try {
+            mService.startTemporarilyDisablingAllNonCarrierMergedWifi(subscriptionId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Re-enable autojoin for all non carrier merged wifi networks temporarily disconnected by
+     * {@link #startTemporarilyDisablingAllNonCarrierMergedWifi(int)}.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void stopTemporarilyDisablingAllNonCarrierMergedWifi() {
+        try {
+            mService.stopTemporarilyDisablingAllNonCarrierMergedWifi();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Save the given network to the list of configured networks for the
      * foreground user. If the network already exists, the configuration
      * is updated. Any new network is enabled by default.
@@ -4246,14 +4807,11 @@
     public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
         ActionListenerProxy listenerProxy = null;
-        Binder binder = null;
         if (listener != null) {
             listenerProxy = new ActionListenerProxy("save", mLooper, listener);
-            binder = new Binder();
         }
         try {
-            mService.save(config, binder, listenerProxy,
-                    listener == null ? 0 : listener.hashCode());
+            mService.save(config, listenerProxy);
         } catch (RemoteException e) {
             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
         } catch (SecurityException e) {
@@ -4283,14 +4841,11 @@
     public void forget(int netId, @Nullable ActionListener listener) {
         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
         ActionListenerProxy listenerProxy = null;
-        Binder binder = null;
         if (listener != null) {
             listenerProxy = new ActionListenerProxy("forget", mLooper, listener);
-            binder = new Binder();
         }
         try {
-            mService.forget(netId, binder, listenerProxy,
-                    listener == null ? 0 : listener.hashCode());
+            mService.forget(netId, listenerProxy);
         } catch (RemoteException e) {
             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
         } catch (SecurityException e) {
@@ -5323,6 +5878,13 @@
     }
 
     /**
+     * @return true if this device supports WPA3 AP validation.
+     */
+    public boolean isWpa3ApValidationSupported() {
+        return isFeatureSupported(WIFI_FEATURE_SAE_PK);
+    }
+
+    /**
      * Gets the factory Wi-Fi MAC addresses.
      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
      * if failed.
@@ -5436,6 +5998,89 @@
     }
 
     /**
+     * Easy Connect Device information maximum allowed length.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40;
+
+    /**
+     * Easy Connect Cryptography Curve name: prime256v1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0;
+
+    /**
+     * Easy Connect Cryptography Curve name: secp384r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1;
+
+    /**
+     * Easy Connect Cryptography Curve name: secp521r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2;
+
+
+    /**
+     * Easy Connect Cryptography Curve name: brainpoolP256r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3;
+
+
+    /**
+     * Easy Connect Cryptography Curve name: brainpoolP384r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4;
+
+
+    /**
+     * Easy Connect Cryptography Curve name: brainpoolP512r1
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5;
+
+    /**
+     * Easy Connect Cryptography Curve name: default
+     * This allows framework to choose manadatory curve prime256v1.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT =
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1;
+
+    /** @hide */
+    @IntDef(prefix = {"EASY_CONNECT_CRYPTOGRAPHY_CURVE_"}, value = {
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1,
+            EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EasyConnectCryptographyCurve {
+    }
+
+    /**
      * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
      * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
      * the specified network using the Easy Connect protocol on an encrypted link.
@@ -5491,6 +6136,52 @@
     }
 
     /**
+     * Start Easy Connect (DPP) in Enrollee-Responder role.
+     * The device will:
+     * 1. Generate a DPP bootstrap URI and return it using the
+     * {@link EasyConnectStatusCallback#onBootstrapUriGenerated(String)} method.
+     * 2. Start DPP as a Responder, waiting for an Initiator device to start the DPP
+     * authentication process.
+     * The caller should use the URI provided in step #1, for instance display it as a QR code
+     * or communicate it in some other way to the initiator device.
+     *
+     * @param deviceInfo      Device specific information to add to the DPP URI. This field allows
+     *                        the users of the configurators to identify the device.
+     *                        Optional - if not provided or in case of an empty string,
+     *                        Info field (I:) will be skipped in the generated DPP URI.
+     *                        Allowed Range of ASCII characters in deviceInfo - %x20-7E.
+     *                        semicolon and space are not allowed.
+     *                        Due to the limitation of maximum allowed characters in QR code,
+     *                        framework limits to a max of
+     *                        {@link #EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH} characters in
+     *                        deviceInfo.
+     *                        Violation of these rules will result in an exception.
+     * @param curve           Elliptic curve cryptography used to generate DPP
+     *                        public/private key pair. If application is not interested in a
+     *                        specific curve, choose default curve
+     *                        {@link #EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT}.
+     * @param callback        Callback for status updates
+     * @param executor        The Executor on which to run the callback.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void startEasyConnectAsEnrolleeResponder(@Nullable String deviceInfo,
+            @EasyConnectCryptographyCurve int curve,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull EasyConnectStatusCallback callback) {
+        Binder binder = new Binder();
+        try {
+            mService.startDppAsEnrolleeResponder(binder, deviceInfo, curve,
+                    new EasyConnectCallbackProxy(executor, callback));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
      * terminate any ongoing transaction, and clean up all associated resources. Caller should not
      * expect any callbacks once this call is made. However, due to the asynchronous nature of
@@ -5564,6 +6255,15 @@
                 mEasyConnectStatusCallback.onProgress(status);
             });
         }
+
+        @Override
+        public void onBootstrapUriGenerated(String uri) {
+            Log.d(TAG, "Easy Connect onBootstrapUriGenerated callback");
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> {
+                mEasyConnectStatusCallback.onBootstrapUriGenerated(uri);
+            });
+        }
     }
 
     /**
@@ -5738,7 +6438,6 @@
                 executor.execute(callback::onScanResultsAvailable);
             }
         }
-
     }
 
     /**
@@ -6236,4 +6935,154 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Sets the state of carrier offload on merged or unmerged networks for specified subscription.
+     *
+     * <p>
+     * When a subscription's carrier network offload is disabled, all network suggestions related to
+     * this subscription will not be considered for auto join.
+     * <p>
+     * If calling app want disable all carrier network offload from a specified subscription, should
+     * call this API twice to disable both merged and unmerged carrier network suggestions.
+     *
+     * @param subscriptionId See {@link SubscriptionInfo#getSubscriptionId()}.
+     * @param merged True for carrier merged network, false otherwise.
+     *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
+     * @param enabled True for enable carrier network offload, false otherwise.
+     * @see #isCarrierNetworkOffloadEnabled(int, boolean)
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged,
+            boolean enabled) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            mService.setCarrierNetworkOffloadEnabled(subscriptionId, merged, enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the carrier network offload state for merged or unmerged networks for specified
+     * subscription.
+     * @param subscriptionId subscription ID see {@link SubscriptionInfo#getSubscriptionId()}
+     * @param merged True for carrier merged network, false otherwise.
+     *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
+     * @return True to indicate that carrier network offload is enabled, false otherwise.
+     * @see #setCarrierNetworkOffloadEnabled(int, boolean, boolean)
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public boolean isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mService.isCarrierNetworkOffloadEnabled(subscriptionId, merged);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Interface for network suggestion user approval status change listener.
+     * Should be implemented by applications and registered using
+     * {@link #addSuggestionUserApprovalStatusListener(Executor,
+     * SuggestionUserApprovalStatusListener)} (
+     */
+    public interface SuggestionUserApprovalStatusListener {
+
+        /**
+         * Called when the user approval status of the App has changed. The current status can be
+         * queried by {@link #getNetworkSuggestionUserApprovalStatus()}
+         */
+        void onUserApprovalStatusChange();
+    }
+
+    private class SuggestionUserApprovalStatusListenerProxy extends
+            ISuggestionUserApprovalStatusListener.Stub {
+        private final Executor mExecutor;
+        private final SuggestionUserApprovalStatusListener mListener;
+
+        SuggestionUserApprovalStatusListenerProxy(@NonNull Executor executor,
+                @NonNull SuggestionUserApprovalStatusListener listener) {
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        @Override
+        public void onUserApprovalStatusChange() {
+            mExecutor.execute(() -> mListener.onUserApprovalStatusChange());
+        }
+
+    }
+
+    /**
+     * Add a listener for Wi-Fi network suggestion user approval status.
+     * See {@link SuggestionUserApprovalStatusListener}.
+     * Caller will receive a callback when the user approval status of the caller has changed.
+     * Caller can remove a previously registered listener using
+     * {@link WifiManager#removeSuggestionUserApprovalStatusListener(
+     * SuggestionUserApprovalStatusListener)}
+     * A caller can add multiple listeners to monitor the event.
+     * @param executor The executor to execute the listener of the {@code listener} object.
+     * @param listener listener for suggestion user approval status changes.
+     * @return true if succeed otherwise false.
+     */
+    @RequiresPermission(ACCESS_WIFI_STATE)
+    public boolean addSuggestionUserApprovalStatusListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull SuggestionUserApprovalStatusListener listener) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
+        if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
+        Log.v(TAG, "addSuggestionUserApprovalStatusListener listener=" + listener
+                + ", executor=" + executor);
+        try {
+            return mService.addSuggestionUserApprovalStatusListener(new Binder(),
+                    new SuggestionUserApprovalStatusListenerProxy(executor, listener),
+                    listener.hashCode(), mContext.getOpPackageName(), mContext.getAttributionTag());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+    }
+
+    /**
+     * Allow callers to remove a previously registered listener using
+     * {@link #addSuggestionUserApprovalStatusListener(Executor,
+     * SuggestionUserApprovalStatusListener)}. After calling this method,
+     * applications will no longer receive network suggestion user approval status change through
+     * that listener.
+     *
+     * @param listener listener to remove.
+     */
+    @RequiresPermission(ACCESS_WIFI_STATE)
+    public void removeSuggestionUserApprovalStatusListener(
+            @NonNull SuggestionUserApprovalStatusListener listener) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
+        Log.v(TAG, "removeSuggestionUserApprovalStatusListener: listener=" + listener);
+        try {
+            mService.removeSuggestionUserApprovalStatusListener(listener.hashCode(),
+                    mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
 }
diff --git a/framework/java/android/net/wifi/WifiNetworkSpecifier.java b/framework/java/android/net/wifi/WifiNetworkSpecifier.java
index e12bb91..be3b45d 100644
--- a/framework/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/framework/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -56,6 +56,16 @@
                 MacAddress.BROADCAST_ADDRESS;
 
         /**
+         * Set WPA Enterprise type according to certificate security level.
+         * This is for backward compatibility in R.
+         */
+        private static final int WPA3_ENTERPRISE_AUTO = 0;
+        /** Set WPA Enterprise type to standard mode only. */
+        private static final int WPA3_ENTERPRISE_STANDARD = 1;
+        /** Set WPA Enterprise type to 192 bit mode only. */
+        private static final int WPA3_ENTERPRISE_192_BIT = 2;
+
+        /**
          * SSID pattern match specified by the app.
          */
         private @Nullable PatternMatcher mSsidPatternMatcher;
@@ -87,6 +97,10 @@
          */
         private @Nullable WifiEnterpriseConfig mWpa3EnterpriseConfig;
         /**
+         * Indicate what type this WPA3-Enterprise network is.
+         */
+        private int mWpa3EnterpriseType = WPA3_ENTERPRISE_AUTO;
+        /**
          * This is a network that does not broadcast its SSID, so an
          * SSID-specific probe request must be used for scans.
          */
@@ -249,9 +263,14 @@
          * sha384WithRSAEncryption (OID 1.2.840.113549.1.1.12) or ecdsa-with-SHA384
          * (OID 1.2.840.10045.4.3.3).
          *
+         * @deprecated use {@link #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)} or
+         * {@link #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)} to specify
+         * WPA3-Enterprise type explicitly.
+         *
          * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
+        @Deprecated
         public @NonNull Builder setWpa3EnterpriseConfig(
                 @NonNull WifiEnterpriseConfig enterpriseConfig) {
             checkNotNull(enterpriseConfig);
@@ -260,6 +279,58 @@
         }
 
         /**
+         * Set the associated enterprise configuration for this network. Needed for authenticating
+         * to standard WPA3-Enterprise networks. See {@link WifiEnterpriseConfig} for description.
+         * For WPA3-Enterprise in 192-bit security mode networks,
+         * see {@link #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)} for description.
+         *
+         * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         */
+        public @NonNull Builder setWpa3EnterpriseStandardModeConfig(
+                @NonNull WifiEnterpriseConfig enterpriseConfig) {
+            checkNotNull(enterpriseConfig);
+            mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+            mWpa3EnterpriseType = WPA3_ENTERPRISE_STANDARD;
+            return this;
+        }
+
+        /**
+         * Set the associated enterprise configuration for this network. Needed for authenticating
+         * to WPA3-Enterprise in 192-bit security mode networks. See {@link WifiEnterpriseConfig}
+         * for description. Both the client and CA certificates must be provided,
+         * and must be of type of either sha384WithRSAEncryption with key length of 3072bit or
+         * more (OID 1.2.840.113549.1.1.12), or ecdsa-with-SHA384 with key length of 384bit or
+         * more (OID 1.2.840.10045.4.3.3).
+         *
+         * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         * @throws IllegalArgumentException if the EAP type or certificates do not
+         *                                  meet 192-bit mode requirements.
+         */
+        public @NonNull Builder setWpa3Enterprise192BitModeConfig(
+                @NonNull WifiEnterpriseConfig enterpriseConfig) {
+            checkNotNull(enterpriseConfig);
+            if (enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.TLS) {
+                throw new IllegalArgumentException("The 192-bit mode network type must be TLS");
+            }
+            if (!WifiEnterpriseConfig.isSuiteBCipherCert(
+                    enterpriseConfig.getClientCertificate())) {
+                throw new IllegalArgumentException(
+                    "The client certificate does not meet 192-bit mode requirements.");
+            }
+            if (!WifiEnterpriseConfig.isSuiteBCipherCert(
+                    enterpriseConfig.getCaCertificate())) {
+                throw new IllegalArgumentException(
+                    "The CA certificate does not meet 192-bit mode requirements.");
+            }
+
+            mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+            mWpa3EnterpriseType = WPA3_ENTERPRISE_192_BIT;
+            return this;
+        }
+
+        /**
          * Specifies whether this represents a hidden network.
          * <p>
          * <li>Setting this disallows the usage of {@link #setSsidPattern(PatternMatcher)} since
@@ -289,23 +360,23 @@
                 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
                 configuration.enterpriseConfig = mWpa2EnterpriseConfig;
             } else if (mWpa3EnterpriseConfig != null) { // WPA3-Enterprise
-                if (mWpa3EnterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS
+                if (mWpa3EnterpriseType == WPA3_ENTERPRISE_AUTO
+                        && mWpa3EnterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS
                         && WifiEnterpriseConfig.isSuiteBCipherCert(
                         mWpa3EnterpriseConfig.getClientCertificate())
                         && WifiEnterpriseConfig.isSuiteBCipherCert(
                         mWpa3EnterpriseConfig.getCaCertificate())) {
-                    // WPA3-Enterprise in 192-bit security mode (Suite-B)
-                    configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
+                    // WPA3-Enterprise in 192-bit security mode
+                    configuration.setSecurityParams(
+                            WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
+                } else if (mWpa3EnterpriseType == WPA3_ENTERPRISE_192_BIT) {
+                    // WPA3-Enterprise in 192-bit security mode
+                    configuration.setSecurityParams(
+                            WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
                 } else {
                     // WPA3-Enterprise
-                    configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
-                    configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
-                    configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
-                    configuration.allowedPairwiseCiphers.set(
-                            WifiConfiguration.PairwiseCipher.GCMP_256);
-                    configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
-                    configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
-                    configuration.requirePmf = true;
+                    configuration.setSecurityParams(
+                            WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
                 }
                 configuration.enterpriseConfig = mWpa3EnterpriseConfig;
             } else if (mIsEnhancedOpen) { // OWE network
diff --git a/framework/java/android/net/wifi/WifiNetworkSuggestion.java b/framework/java/android/net/wifi/WifiNetworkSuggestion.java
index d8be1d2..b7450c5 100644
--- a/framework/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/framework/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -24,12 +24,18 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.net.MacAddress;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
@@ -51,6 +57,16 @@
         private static final int UNASSIGNED_PRIORITY = -1;
 
         /**
+         * Set WPA Enterprise type according to certificate security level.
+         * This is for backward compatibility in R.
+         */
+        private static final int WPA3_ENTERPRISE_AUTO = 0;
+        /** Set WPA Enterprise type to standard mode only. */
+        private static final int WPA3_ENTERPRISE_STANDARD = 1;
+        /** Set WPA Enterprise type to 192 bit mode only. */
+        private static final int WPA3_ENTERPRISE_192_BIT = 2;
+
+        /**
          * SSID of the network.
          */
         private String mSsid;
@@ -81,6 +97,10 @@
          */
         private @Nullable WifiEnterpriseConfig mWpa3EnterpriseConfig;
         /**
+         * Indicate what type this WPA3-Enterprise network is.
+         */
+        private int mWpa3EnterpriseType = WPA3_ENTERPRISE_AUTO;
+        /**
          * The passpoint config for use with Hotspot 2.0 network
          */
         private @Nullable PasspointConfiguration mPasspointConfiguration;
@@ -102,10 +122,15 @@
          */
         private int mMeteredOverride;
         /**
-         * Priority of this network among other network suggestions provided by the app.
+         * Priority of this network among other network suggestions from same priority group
+         * provided by the app.
          * The lower the number, the higher the priority (i.e value of 0 = highest priority).
          */
         private int mPriority;
+        /**
+         * Priority group ID, while suggestion priority will only effect inside the priority group.
+         */
+        private int mPriorityGroup;
 
         /**
          * The carrier ID identifies the operator who provides this network configuration.
@@ -114,6 +139,12 @@
         private int mCarrierId;
 
         /**
+         * The Subscription ID identifies the SIM card for which this network configuration is
+         * valid.
+         */
+        private int mSubscriptionId;
+
+        /**
          * Whether this network is shared credential with user to allow user manually connect.
          */
         private boolean mIsSharedWithUser;
@@ -144,6 +175,27 @@
          */
         private boolean mIsNetworkUntrusted;
 
+        /**
+         * Whether this network will be brought up as OEM paid (OEM_PAID capability bit added).
+         */
+        private boolean mIsNetworkOemPaid;
+
+        /**
+         * Whether this network will be brought up as OEM private (OEM_PRIVATE capability bit
+         * added).
+         */
+        private boolean mIsNetworkOemPrivate;
+
+        /**
+         * Whether this network is a carrier merged network.
+         */
+        private boolean mIsCarrierMerged;
+
+        /**
+         * Whether this network will use enhanced MAC randomization.
+         */
+        private boolean mIsEnhancedMacRandomizationEnabled;
+
         public Builder() {
             mSsid = null;
             mBssid =  null;
@@ -165,6 +217,12 @@
             mWapiPskPassphrase = null;
             mWapiEnterpriseConfig = null;
             mIsNetworkUntrusted = false;
+            mIsNetworkOemPaid = false;
+            mIsNetworkOemPrivate = false;
+            mIsCarrierMerged = false;
+            mPriorityGroup = 0;
+            mIsEnhancedMacRandomizationEnabled = false;
+            mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
 
         /**
@@ -282,11 +340,16 @@
          * sha384WithRSAEncryption (OID 1.2.840.113549.1.1.12) or ecdsa-with-SHA384
          * (OID 1.2.840.10045.4.3.3).
          *
+         * @deprecated use {@link #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)} or
+         * {@link #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)} to specify
+         * WPA3-Enterprise type explicitly.
+         *
          * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          * @throws IllegalArgumentException if configuration CA certificate or
          *                                  AltSubjectMatch/DomainSuffixMatch is not set.
          */
+        @Deprecated
         public @NonNull Builder setWpa3EnterpriseConfig(
                 @NonNull WifiEnterpriseConfig enterpriseConfig) {
             checkNotNull(enterpriseConfig);
@@ -298,6 +361,63 @@
         }
 
         /**
+         * Set the associated enterprise configuration for this network. Needed for authenticating
+         * to WPA3-Enterprise standard networks. See {@link WifiEnterpriseConfig} for description.
+         * For WPA3-Enterprise in 192-bit security mode networks,
+         * see {@link #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)} for description.
+         *
+         * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         * @throws IllegalArgumentException if configuration CA certificate or
+         *                                  AltSubjectMatch/DomainSuffixMatch is not set.
+         */
+        public @NonNull Builder setWpa3EnterpriseStandardModeConfig(
+                @NonNull WifiEnterpriseConfig enterpriseConfig) {
+            checkNotNull(enterpriseConfig);
+            if (enterpriseConfig.isInsecure()) {
+                throw new IllegalArgumentException("Enterprise configuration is insecure");
+            }
+            mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+            mWpa3EnterpriseType = WPA3_ENTERPRISE_STANDARD;
+            return this;
+        }
+
+        /**
+         * Set the associated enterprise configuration for this network. Needed for authenticating
+         * to WPA3-Enterprise in 192-bit security mode networks. See {@link WifiEnterpriseConfig}
+         * for description. Both the client and CA certificates must be provided,
+         * and must be of type of either sha384WithRSAEncryption with key length of 3072bit or
+         * more (OID 1.2.840.113549.1.1.12), or ecdsa-with-SHA384 with key length of 384bit or
+         * more (OID 1.2.840.10045.4.3.3).
+         *
+         * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         * @throws IllegalArgumentException if the EAP type or certificates do not
+         *                                  meet 192-bit mode requirements.
+         */
+        public @NonNull Builder setWpa3Enterprise192BitModeConfig(
+                @NonNull WifiEnterpriseConfig enterpriseConfig) {
+            checkNotNull(enterpriseConfig);
+            if (enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.TLS) {
+                throw new IllegalArgumentException("The 192-bit mode network type must be TLS");
+            }
+            if (!WifiEnterpriseConfig.isSuiteBCipherCert(
+                    enterpriseConfig.getClientCertificate())) {
+                throw new IllegalArgumentException(
+                    "The client certificate does not meet 192-bit mode requirements.");
+            }
+            if (!WifiEnterpriseConfig.isSuiteBCipherCert(
+                    enterpriseConfig.getCaCertificate())) {
+                throw new IllegalArgumentException(
+                    "The CA certificate does not meet 192-bit mode requirements.");
+            }
+
+            mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+            mWpa3EnterpriseType = WPA3_ENTERPRISE_192_BIT;
+            return this;
+        }
+
+        /**
          * Set the associated Passpoint configuration for this network. Needed for authenticating
          * to Hotspot 2.0 networks. See {@link PasspointConfiguration} for description.
          *
@@ -333,6 +453,42 @@
         }
 
         /**
+         * Set the subscription ID of the SIM card for which this suggestion is targeted.
+         * The suggestion will only apply to that SIM card.
+         * <p>
+         * The subscription ID must belong to a carrier ID which meets either of the following
+         * conditions:
+         * <li>The carrier ID specified by the cross carrier provider, or</li>
+         * <li>The carrier ID which is used to validate the suggesting carrier-privileged app, see
+         * {@link TelephonyManager#hasCarrierPrivileges()}</li>
+         *
+         * @param subId subscription ID see {@link SubscriptionInfo#getSubscriptionId()}
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         */
+        public @NonNull Builder setSubscriptionId(int subId) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            mSubscriptionId = subId;
+            return this;
+        }
+
+        /**
+         * Set the priority group ID, {@link #setPriority(int)} will only impact the network
+         * suggestions from the same priority group within the same app.
+         *
+         * @param priorityGroup priority group id, if not set default is 0.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         */
+        public @NonNull Builder setPriorityGroup(int priorityGroup) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            mPriorityGroup = priorityGroup;
+            return this;
+        }
+
+        /**
          * Set the ASCII WAPI passphrase for this network. Needed for authenticating to
          * WAPI-PSK networks.
          *
@@ -380,6 +536,30 @@
         }
 
         /**
+         * Specifies the MAC randomization method.
+         * <p>
+         * Suggested networks will never use the device (factory) MAC address to associate to the
+         * network - instead they use a locally generated random MAC address. This method controls
+         * the strategy for generating the random MAC address:
+         * <li> Persisted MAC randomization (false - the default): generates the MAC address from a
+         * secret seed and information from the Wi-Fi configuration (SSID or Passpoint profile).
+         * This means that the same generated MAC address will be used for each subsequent
+         * association. </li>
+         * <li> Enhanced MAC randomization (true): periodically generates a new MAC
+         * address for new connections. Under this option, the randomized MAC address should change
+         * if the suggestion is removed and then added back. </li>
+         *
+         * @param enabled {@code true} to periodically change the randomized MAC address.
+         *                {@code false} to use the same randomized MAC for all connections to this
+         *                            network.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         */
+        public @NonNull Builder setIsEnhancedMacRandomizationEnabled(boolean enabled) {
+            mIsEnhancedMacRandomizationEnabled = enabled;
+            return this;
+        }
+
+        /**
          * Specifies whether the app needs to log in to a captive portal to obtain Internet access.
          * <p>
          * This will dictate if the directed broadcast
@@ -415,8 +595,9 @@
 
         /**
          * Specify the priority of this network among other network suggestions provided by the same
-         * app (priorities have no impact on suggestions by different apps). The higher the number,
-         * the higher the priority (i.e value of 0 = lowest priority).
+         * app (priorities have no impact on suggestions by different apps) and within the same
+         * priority group, see {@link #setPriorityGroup(int)}.
+         * The higher the number, the higher the priority (i.e value of 0 = lowest priority).
          * <p>
          * <li>If not set, defaults a lower priority than any assigned priority.</li>
          *
@@ -494,12 +675,15 @@
 
         /**
          * Specifies whether the system will bring up the network (if selected) as untrusted. An
-         * untrusted network has its {@link android.net.NetworkCapabilities#NET_CAPABILITY_TRUSTED}
+         * untrusted network has its {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED}
          * capability removed. The Wi-Fi network selection process may use this information to
          * influence priority of the suggested network for Wi-Fi network selection (most likely to
          * reduce it). The connectivity service may use this information to influence the overall
          * network configuration of the device.
          * <p>
+         * <li> These suggestions are only considered for network selection if a
+         * {@link NetworkRequest} without {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED}
+         * capability is filed.
          * <li> An untrusted network's credentials may not be shared with the user using
          * {@link #setCredentialSharedWithUser(boolean)}.</li>
          * <li> If not set, defaults to false (i.e. network is trusted).</li>
@@ -513,6 +697,118 @@
             return this;
         }
 
+        /**
+         * Specifies whether the system will bring up the network (if selected) as OEM paid. An
+         * OEM paid network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID} capability
+         * added.
+         * Note:
+         * <li>The connectivity service may use this information to influence the overall
+         * network configuration of the device. This network is typically only available to system
+         * apps.
+         * <li>On devices which do not support concurrent connection (indicated via
+         * {@link WifiManager#isMultiStaConcurrencySupported()}, Wi-Fi network selection process may
+         * use this information to influence priority of the suggested network for Wi-Fi network
+         * selection (most likely to reduce it).
+         * <li>On devices which support more than 1 concurrent connections (indicated via
+         * {@link WifiManager#isMultiStaConcurrencySupported()}, these OEM paid networks will be
+         * brought up as a secondary concurrent connection (primary connection will be used
+         * for networks available to the user and all apps.
+         * <p>
+         * <li> An OEM paid network's credentials may not be shared with the user using
+         * {@link #setCredentialSharedWithUser(boolean)}.</li>
+         * <li> These suggestions are only considered for network selection if a
+         * {@link NetworkRequest} with {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}
+         * capability is filed.
+         * <li> Each suggestion can have both {@link #setOemPaid(boolean)} and
+         * {@link #setOemPrivate(boolean)} set if the app wants these suggestions considered
+         * for creating either an OEM paid network or OEM private network determined based on
+         * the {@link NetworkRequest} that is active.
+         * <li> If not set, defaults to false (i.e. network is not OEM paid).</li>
+         *
+         * @param isOemPaid Boolean indicating whether the network should be brought up as OEM paid
+         *                  (if true) or not OEM paid (if false).
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setOemPaid(boolean isOemPaid) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            mIsNetworkOemPaid = isOemPaid;
+            return this;
+        }
+
+        /**
+         * Specifies whether the system will bring up the network (if selected) as OEM private. An
+         * OEM private network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE} capability
+         * added.
+         * Note:
+         * <li>The connectivity service may use this information to influence the overall
+         * network configuration of the device. This network is typically only available to system
+         * apps.
+         * <li>On devices which do not support concurrent connection (indicated via
+         * {@link WifiManager#isMultiStaConcurrencySupported()}, Wi-Fi network selection process may
+         * use this information to influence priority of the suggested network for Wi-Fi network
+         * selection (most likely to reduce it).
+         * <li>On devices which support more than 1 concurrent connections (indicated via
+         * {@link WifiManager#isMultiStaConcurrencySupported()}, these OEM private networks will be
+         * brought up as a secondary concurrent connection (primary connection will be used
+         * for networks available to the user and all apps.
+         * <p>
+         * <li> An OEM private network's credentials may not be shared with the user using
+         * {@link #setCredentialSharedWithUser(boolean)}.</li>
+         * <li> These suggestions are only considered for network selection if a
+         * {@link NetworkRequest} with {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}
+         * capability is filed.
+         * <li> Each suggestion can have both {@link #setOemPaid(boolean)} and
+         * {@link #setOemPrivate(boolean)} set if the app wants these suggestions considered
+         * for creating either an OEM paid network or OEM private network determined based on
+         * the {@link NetworkRequest} that is active.
+         * <li> If not set, defaults to false (i.e. network is not OEM private).</li>
+         *
+         * @param isOemPrivate Boolean indicating whether the network should be brought up as OEM
+         *                     private (if true) or not OEM private (if false).
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         * @hide
+         */
+        @SystemApi
+        public @NonNull Builder setOemPrivate(boolean isOemPrivate) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            mIsNetworkOemPrivate = isOemPrivate;
+            return this;
+        }
+
+        /**
+         * Specifies whether the suggestion represents a carrier merged network. A carrier merged
+         * Wi-Fi network is treated as part of the mobile carrier network. Such configuration may
+         * impact the user interface and data usage accounting.
+         * <p>
+         * <li>A suggestion marked as carrier merged must be metered enterprise network with a valid
+         * subscription Id set.
+         * @see #setIsMetered(boolean)
+         * @see #setSubscriptionId(int)
+         * @see #setWpa2EnterpriseConfig(WifiEnterpriseConfig)
+         * @see #setWpa3Enterprise192BitModeConfig(WifiEnterpriseConfig)
+         * @see #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)
+         * @see #setPasspointConfig(PasspointConfiguration)
+         * </li>
+         * <li>If not set, defaults to false (i.e. not a carrier merged network.)</li>
+         * </p>
+         * @param isCarrierMerged Boolean indicating whether the network is treated a carrier
+         *                               merged network (if true) or non-merged network (if false);
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         */
+        public @NonNull Builder setCarrierMerged(boolean isCarrierMerged) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            mIsCarrierMerged = isCarrierMerged;
+            return this;
+        }
+
         private void setSecurityParamsInWifiConfiguration(
                 @NonNull WifiConfiguration configuration) {
             if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
@@ -527,23 +823,23 @@
                 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
                 configuration.enterpriseConfig = mWpa2EnterpriseConfig;
             } else if (mWpa3EnterpriseConfig != null) { // WPA3-Enterprise
-                if (mWpa3EnterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS
+                if (mWpa3EnterpriseType == WPA3_ENTERPRISE_AUTO
+                        && mWpa3EnterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS
                         && WifiEnterpriseConfig.isSuiteBCipherCert(
                         mWpa3EnterpriseConfig.getClientCertificate())
                         && WifiEnterpriseConfig.isSuiteBCipherCert(
                         mWpa3EnterpriseConfig.getCaCertificate())) {
-                    // WPA3-Enterprise in 192-bit security mode (Suite-B)
-                    configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
+                    // WPA3-Enterprise in 192-bit security mode
+                    configuration.setSecurityParams(
+                            WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
+                } else if (mWpa3EnterpriseType == WPA3_ENTERPRISE_192_BIT) {
+                    // WPA3-Enterprise in 192-bit security mode
+                    configuration.setSecurityParams(
+                            WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
                 } else {
                     // WPA3-Enterprise
-                    configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
-                    configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
-                    configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
-                    configuration.allowedPairwiseCiphers.set(
-                            WifiConfiguration.PairwiseCipher.GCMP_256);
-                    configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
-                    configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
-                    configuration.requirePmf = true;
+                    configuration.setSecurityParams(
+                            WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
                 }
                 configuration.enterpriseConfig = mWpa3EnterpriseConfig;
             } else if (mIsEnhancedOpen) { // OWE network
@@ -579,6 +875,13 @@
             wifiConfiguration.meteredOverride = mMeteredOverride;
             wifiConfiguration.carrierId = mCarrierId;
             wifiConfiguration.trusted = !mIsNetworkUntrusted;
+            wifiConfiguration.oemPaid = mIsNetworkOemPaid;
+            wifiConfiguration.oemPrivate = mIsNetworkOemPrivate;
+            wifiConfiguration.carrierMerged = mIsCarrierMerged;
+            wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
+                    ? WifiConfiguration.RANDOMIZATION_ENHANCED
+                    : WifiConfiguration.RANDOMIZATION_PERSISTENT;
+            wifiConfiguration.subscriptionId = mSubscriptionId;
             return wifiConfiguration;
         }
 
@@ -607,8 +910,19 @@
             wifiConfiguration.priority = mPriority;
             wifiConfiguration.meteredOverride = mMeteredOverride;
             wifiConfiguration.trusted = !mIsNetworkUntrusted;
+            wifiConfiguration.oemPaid = mIsNetworkOemPaid;
+            wifiConfiguration.oemPrivate = mIsNetworkOemPrivate;
+            wifiConfiguration.carrierMerged = mIsCarrierMerged;
+            wifiConfiguration.subscriptionId = mSubscriptionId;
             mPasspointConfiguration.setCarrierId(mCarrierId);
+            mPasspointConfiguration.setSubscriptionId(mSubscriptionId);
             mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
+            mPasspointConfiguration.setOemPrivate(mIsNetworkOemPrivate);
+            mPasspointConfiguration.setOemPaid(mIsNetworkOemPaid);
+            mPasspointConfiguration.setCarrierMerged(mIsCarrierMerged);
+            wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
+                    ? WifiConfiguration.RANDOMIZATION_ENHANCED
+                    : WifiConfiguration.RANDOMIZATION_PERSISTENT;
             return wifiConfiguration;
         }
 
@@ -677,6 +991,8 @@
                             + "suggestion with Passpoint configuration");
                 }
                 wifiConfiguration = buildWifiConfigurationForPasspoint();
+                mPasspointConfiguration.setEnhancedMacRandomizationEnabled(
+                        mIsEnhancedMacRandomizationEnabled);
             } else {
                 if (mSsid == null) {
                     throw new IllegalStateException("setSsid should be invoked for suggestion");
@@ -707,20 +1023,52 @@
                 if (mIsSharedWithUserSet && mIsSharedWithUser) {
                     throw new IllegalStateException("Should not be both"
                             + "setCredentialSharedWithUser and +"
-                            + "setIsNetworkAsUntrusted to true");
+                            + "setUntrusted to true");
                 }
                 mIsSharedWithUser = false;
             }
+            if (mIsNetworkOemPaid) {
+                if (mIsSharedWithUserSet && mIsSharedWithUser) {
+                    throw new IllegalStateException("Should not be both"
+                            + "setCredentialSharedWithUser and +"
+                            + "setOemPaid to true");
+                }
+                mIsSharedWithUser = false;
+            }
+            if (mIsNetworkOemPrivate) {
+                if (mIsSharedWithUserSet && mIsSharedWithUser) {
+                    throw new IllegalStateException("Should not be both"
+                            + "setCredentialSharedWithUser and +"
+                            + "setOemPrivate to true");
+                }
+                mIsSharedWithUser = false;
+            }
+            if (mIsCarrierMerged) {
+                if (mSubscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
+                        || mMeteredOverride != WifiConfiguration.METERED_OVERRIDE_METERED
+                        || !isEnterpriseSuggestion()) {
+                    throw new IllegalStateException("A carrier merged network must be a metered, "
+                            + "enterprise network with valid subscription Id");
+                }
+            }
             return new WifiNetworkSuggestion(
                     wifiConfiguration,
                     mPasspointConfiguration,
                     mIsAppInteractionRequired,
                     mIsUserInteractionRequired,
                     mIsSharedWithUser,
-                    mIsInitialAutojoinEnabled);
+                    mIsInitialAutojoinEnabled,
+                    mPriorityGroup);
+        }
+
+        private boolean isEnterpriseSuggestion() {
+            return !(mWpa2EnterpriseConfig == null && mWpa3EnterpriseConfig == null
+                    && mWapiEnterpriseConfig == null && mPasspointConfiguration == null);
         }
     }
 
+
+
     /**
      * Network configuration for the provided network.
      * @hide
@@ -760,6 +1108,12 @@
      */
     public final boolean isInitialAutoJoinEnabled;
 
+    /**
+     * Priority group ID.
+     * @hide
+     */
+    public final int priorityGroup;
+
     /** @hide */
     public WifiNetworkSuggestion() {
         this.wifiConfiguration = new WifiConfiguration();
@@ -768,6 +1122,7 @@
         this.isUserInteractionRequired = false;
         this.isUserAllowedToManuallyConnect = true;
         this.isInitialAutoJoinEnabled = true;
+        this.priorityGroup = 0;
     }
 
     /** @hide */
@@ -776,7 +1131,7 @@
                                  boolean isAppInteractionRequired,
                                  boolean isUserInteractionRequired,
                                  boolean isUserAllowedToManuallyConnect,
-                                 boolean isInitialAutoJoinEnabled) {
+                                 boolean isInitialAutoJoinEnabled, int priorityGroup) {
         checkNotNull(networkConfiguration);
         this.wifiConfiguration = networkConfiguration;
         this.passpointConfiguration = passpointConfiguration;
@@ -785,6 +1140,7 @@
         this.isUserInteractionRequired = isUserInteractionRequired;
         this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
         this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
+        this.priorityGroup = priorityGroup;
     }
 
     public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -797,7 +1153,8 @@
                             in.readBoolean(), // isAppInteractionRequired
                             in.readBoolean(), // isUserInteractionRequired
                             in.readBoolean(), // isSharedCredentialWithUser
-                            in.readBoolean()  // isAutojoinEnabled
+                            in.readBoolean(),  // isAutojoinEnabled
+                            in.readInt() // priorityGroup
                     );
                 }
 
@@ -820,12 +1177,15 @@
         dest.writeBoolean(isUserInteractionRequired);
         dest.writeBoolean(isUserAllowedToManuallyConnect);
         dest.writeBoolean(isInitialAutoJoinEnabled);
+        dest.writeInt(priorityGroup);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID,
-                wifiConfiguration.allowedKeyManagement, wifiConfiguration.getKey());
+                wifiConfiguration.getDefaultSecurityType(),
+                wifiConfiguration.getPasspointUniqueId(),
+                wifiConfiguration.subscriptionId, wifiConfiguration.carrierId);
     }
 
     /**
@@ -846,10 +1206,12 @@
 
         return TextUtils.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID)
                 && TextUtils.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID)
-                && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
-                lhs.wifiConfiguration.allowedKeyManagement)
-                && TextUtils.equals(this.wifiConfiguration.getKey(),
-                lhs.wifiConfiguration.getKey());
+                && TextUtils.equals(this.wifiConfiguration.getDefaultSecurityType(),
+                lhs.wifiConfiguration.getDefaultSecurityType())
+                && TextUtils.equals(this.wifiConfiguration.getPasspointUniqueId(),
+                lhs.wifiConfiguration.getPasspointUniqueId())
+                && this.wifiConfiguration.carrierId == lhs.wifiConfiguration.carrierId
+                && this.wifiConfiguration.subscriptionId == lhs.wifiConfiguration.subscriptionId;
     }
 
     @Override
@@ -863,6 +1225,10 @@
                 .append(", isCredentialSharedWithUser=").append(isUserAllowedToManuallyConnect)
                 .append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
                 .append(", isUnTrusted=").append(!wifiConfiguration.trusted)
+                .append(", isOemPaid=").append(wifiConfiguration.oemPaid)
+                .append(", isOemPrivate=").append(wifiConfiguration.oemPrivate)
+                .append(", isCarrierMerged").append(wifiConfiguration.carrierMerged)
+                .append(", priorityGroup=").append(priorityGroup)
                 .append(" ]");
         return sb.toString();
     }
@@ -957,6 +1323,40 @@
     }
 
     /**
+     * @see Builder#setOemPaid(boolean)
+     * @hide
+     */
+    @SystemApi
+    public boolean isOemPaid() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return wifiConfiguration.oemPaid;
+    }
+
+    /**
+     * @see Builder#setOemPrivate(boolean)
+     * @hide
+     */
+    @SystemApi
+    public boolean isOemPrivate() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return wifiConfiguration.oemPrivate;
+    }
+
+    /**
+     * @see Builder#setCarrierMerged(boolean)
+     */
+    public boolean isCarrierMerged() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return wifiConfiguration.carrierMerged;
+    }
+
+    /**
      * Get the WifiEnterpriseConfig, or null if unset.
      * @see Builder#setWapiEnterpriseConfig(WifiEnterpriseConfig)
      * @see Builder#setWpa2EnterpriseConfig(WifiEnterpriseConfig)
@@ -983,4 +1383,24 @@
         }
         return WifiInfo.removeDoubleQuotes(wifiConfiguration.preSharedKey);
     }
+
+    /**
+     * @see Builder#setPriorityGroup(int)
+     */
+    public int getPriorityGroup() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return priorityGroup;
+    }
+
+    /**
+     * @see Builder#setSubscriptionId(int)
+     */
+    public int getSubscriptionId() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return wifiConfiguration.subscriptionId;
+    }
 }
diff --git a/framework/java/android/net/wifi/WifiScanner.java b/framework/java/android/net/wifi/WifiScanner.java
index 4163c88..7c051f0 100644
--- a/framework/java/android/net/wifi/WifiScanner.java
+++ b/framework/java/android/net/wifi/WifiScanner.java
@@ -68,7 +68,9 @@
     /** @hide */
     public static final int WIFI_BAND_INDEX_6_GHZ = 3;
     /** @hide */
-    public static final int WIFI_BAND_COUNT = 4;
+    public static final int WIFI_BAND_INDEX_60_GHZ = 4;
+    /** @hide */
+    public static final int WIFI_BAND_COUNT = 5;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -76,7 +78,8 @@
             WIFI_BAND_INDEX_24_GHZ,
             WIFI_BAND_INDEX_5_GHZ,
             WIFI_BAND_INDEX_5_GHZ_DFS_ONLY,
-            WIFI_BAND_INDEX_6_GHZ})
+            WIFI_BAND_INDEX_6_GHZ,
+            WIFI_BAND_INDEX_60_GHZ})
     public @interface WifiBandIndex {}
 
     /** no band specified; use channel list instead */
@@ -89,6 +92,8 @@
     public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 1 << WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
     /** 6 GHz band */
     public static final int WIFI_BAND_6_GHZ = 1 << WIFI_BAND_INDEX_6_GHZ;
+    /** 60 GHz band */
+    public static final int WIFI_BAND_60_GHZ = 1 << WIFI_BAND_INDEX_60_GHZ;
 
     /**
      * Combination of bands
@@ -113,6 +118,12 @@
     /** 2.4 GHz band and 5 GHz band; with DFS channels and 6 GHz */
     public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ =
             WIFI_BAND_BOTH_WITH_DFS | WIFI_BAND_6_GHZ;
+    /** @hide */
+    public static final int WIFI_BAND_24_5_6_60_GHZ =
+            WIFI_BAND_24_5_6_GHZ | WIFI_BAND_60_GHZ;
+    /** @hide */
+    public static final int WIFI_BAND_24_5_WITH_DFS_6_60_GHZ =
+            WIFI_BAND_24_5_6_60_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -127,7 +138,10 @@
             WIFI_BAND_BOTH_WITH_DFS,
             WIFI_BAND_6_GHZ,
             WIFI_BAND_24_5_6_GHZ,
-            WIFI_BAND_24_5_WITH_DFS_6_GHZ})
+            WIFI_BAND_24_5_WITH_DFS_6_GHZ,
+            WIFI_BAND_60_GHZ,
+            WIFI_BAND_24_5_6_60_GHZ,
+            WIFI_BAND_24_5_WITH_DFS_6_60_GHZ})
     public @interface WifiBand {}
 
     /**
@@ -179,7 +193,8 @@
      * @hide
      */
     public static boolean isFullBandScan(@WifiBand int bandScanned, boolean excludeDfs) {
-        return (bandScanned | WIFI_BAND_6_GHZ | (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))
+        return (bandScanned | WIFI_BAND_6_GHZ | WIFI_BAND_60_GHZ
+                | (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))
                 == WIFI_BAND_ALL;
     }
 
@@ -571,6 +586,19 @@
             }
         }
 
+        /** {@hide} */
+        public void addResults(@NonNull ScanData s) {
+            mBandScanned |= s.mBandScanned;
+            mFlags |= s.mFlags;
+            addResults(s.getResults());
+        }
+
+        /** {@hide} */
+        public boolean isFullBandScanResults() {
+            return (mBandScanned & WifiScanner.WIFI_BAND_24_GHZ) != 0
+                && (mBandScanned & WifiScanner.WIFI_BAND_5_GHZ) != 0;
+        }
+
         /** Implement the Parcelable interface {@hide} */
         public int describeContents() {
             return 0;
diff --git a/framework/java/android/net/wifi/aware/AwareResources.java b/framework/java/android/net/wifi/aware/AwareResources.java
new file mode 100644
index 0000000..cee1f40
--- /dev/null
+++ b/framework/java/android/net/wifi/aware/AwareResources.java
@@ -0,0 +1,146 @@
+/*
+ * 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.aware;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The resources of the Aware service.
+ */
+public final class AwareResources implements Parcelable {
+    /**
+     * Number of the NDPs are available.
+     */
+    private int mNumOfAvailableNdps;
+
+    /**
+     * Number of the publish sessions are available.
+     */
+    private int mNumOfAvailablePublishSessions;
+
+    /**
+     * Number of the subscribe sessions are available.
+     */
+    private int mNumOfAvailableSubscribeSessions;
+
+    /**
+     * @hide : should not be created by apps
+     */
+    public AwareResources() {
+    }
+
+    /**
+     * Return the number of Aware data-paths (also known as NDPs - NAN Data Paths) which an app
+     * could create. Please refer to the {@link WifiAwareNetworkSpecifier} to create
+     * a Network Specifier and request a data-path.
+     * <p>
+     * Note that these resources aren't reserved - other apps could use them by the time you
+     * attempt to create a data-path.
+     * </p>
+     * @return A Non-negative integer, number of data-paths that could be created.
+     */
+    public int getNumOfAvailableDataPaths() {
+        return mNumOfAvailableNdps;
+    }
+
+    /**
+     * Return the number of Aware publish sessions which an app could create. Please refer to the
+     * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)}
+     * to create a publish session.
+     * <p>
+     * Note that these resources aren't reserved - other apps could use them by the time you
+     * attempt to create a publish session.
+     * </p>
+     * @return A Non-negative integer, number of publish sessions that could be created.
+     */
+    public int getNumOfAvailablePublishSessions() {
+        return mNumOfAvailablePublishSessions;
+    }
+
+    /**
+     * Return the number of Aware subscribe sessions which an app could create. Please refer to the
+     * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}
+     * to create a publish session.
+     * <p>
+     * Note that these resources aren't reserved - other apps could use them by the time you
+     * attempt to create a subscribe session.
+     * </p>
+     * @return A Non-negative integer, number of subscribe sessions that could be created.
+     */
+    public int getNumOfAvailableSubscribeSessions() {
+        return mNumOfAvailableSubscribeSessions;
+    }
+
+    /**
+     * Set the number of the available NDPs.
+     * @hide
+     * @param numOfAvailableNdps Number of available NDPs.
+     */
+    public void setNumOfAvailableDataPaths(int numOfAvailableNdps) {
+        mNumOfAvailableNdps = numOfAvailableNdps;
+    }
+
+    /**
+     * Set the number of the available publish sessions.
+     * @hide
+     * @param numOfAvailablePublishSessions Number of available publish sessions.
+     */
+    public void setNumOfAvailablePublishSessions(int numOfAvailablePublishSessions) {
+        mNumOfAvailablePublishSessions = numOfAvailablePublishSessions;
+    }
+
+    /**
+     * Set the number of the available subscribe sessions.
+     * @hide
+     * @param numOfAvailableSubscribeSessions Number of available subscribe sessions.
+     */
+    public void setNumOfAvailableSubscribeSessions(int numOfAvailableSubscribeSessions) {
+        mNumOfAvailableSubscribeSessions = numOfAvailableSubscribeSessions;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mNumOfAvailableNdps);
+        dest.writeInt(mNumOfAvailablePublishSessions);
+        dest.writeInt(mNumOfAvailableSubscribeSessions);
+    }
+
+    public static final @android.annotation.NonNull Creator<AwareResources> CREATOR =
+            new Creator<AwareResources>() {
+                @Override
+                public AwareResources createFromParcel(Parcel in) {
+                    AwareResources awareResources = new AwareResources();
+                    awareResources.setNumOfAvailableDataPaths(in.readInt());
+                    awareResources.setNumOfAvailablePublishSessions(in.readInt());
+                    awareResources.setNumOfAvailableSubscribeSessions(in.readInt());
+                    return awareResources;
+                }
+
+                @Override
+                public AwareResources[] newArray(int size) {
+                    return new AwareResources[size];
+                }
+            };
+}
diff --git a/framework/java/android/net/wifi/aware/Characteristics.java b/framework/java/android/net/wifi/aware/Characteristics.java
index d5fd48e..9bdda7f 100644
--- a/framework/java/android/net/wifi/aware/Characteristics.java
+++ b/framework/java/android/net/wifi/aware/Characteristics.java
@@ -21,6 +21,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -37,6 +39,9 @@
     public static final String KEY_MAX_MATCH_FILTER_LENGTH = "key_max_match_filter_length";
     /** @hide */
     public static final String KEY_SUPPORTED_CIPHER_SUITES = "key_supported_cipher_suites";
+    /** @hide */
+    public static final String KEY_IS_INSTANT_COMMUNICATION_MODE_SUPPORTED =
+            "key_is_instant_communication_mode_supported";
 
     private Bundle mCharacteristics = new Bundle();
 
@@ -83,6 +88,17 @@
         return mCharacteristics.getInt(KEY_MAX_MATCH_FILTER_LENGTH);
     }
 
+    /**
+     * Check if instant communication mode is supported by device.
+     * @return True if supported, false otherwise.
+     */
+    public boolean isInstantCommunicationModeSupported() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mCharacteristics.getBoolean(KEY_IS_INSTANT_COMMUNICATION_MODE_SUPPORTED);
+    }
+
     /** @hide */
     @IntDef(flag = true, prefix = { "WIFI_AWARE_CIPHER_SUITE_" }, value = {
             WIFI_AWARE_CIPHER_SUITE_NCS_SK_128,
diff --git a/framework/java/android/net/wifi/aware/DiscoverySessionCallback.java b/framework/java/android/net/wifi/aware/DiscoverySessionCallback.java
index bfb0462..da8e17e 100644
--- a/framework/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/framework/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -189,4 +189,20 @@
     public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
         /* empty */
     }
+
+    /**
+     * Called when the discovered service is not available. All further operations on this
+     * discovery session will fail. If the service is available again,
+     * {@link #onServiceDiscovered(PeerHandle, byte[], List)} or
+     * {@link #onServiceDiscoveredWithinRange(PeerHandle, byte[], List, int)} will be called.
+     *
+     * @param peerHandle An opaque handle to the peer matching our discovery operation.
+     * @param reason Discovered service lost reason code. One of
+     *               {@link WifiAwareManager#WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE},
+     *               {@link WifiAwareManager#WIFI_AWARE_DISCOVERY_LOST_REASON_UNKNOWN
+     */
+    public void onServiceLost(@NonNull PeerHandle peerHandle,
+            @WifiAwareManager.DiscoveryLostReasonCode int reason) {
+        /* empty */
+    }
 }
diff --git a/framework/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl b/framework/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl
index 421a8af..e3e7c8e 100644
--- a/framework/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl
+++ b/framework/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl
@@ -35,4 +35,5 @@
     void onMessageSendSuccess(int messageId);
     void onMessageSendFail(int messageId, int reason);
     void onMessageReceived(int peerId, in byte[] message);
+    void onMatchExpired(int peerId);
 }
diff --git a/framework/java/android/net/wifi/aware/IWifiAwareManager.aidl b/framework/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 88f95ad..c90c4d8 100644
--- a/framework/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/framework/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -25,6 +25,7 @@
 import android.net.wifi.aware.PublishConfig;
 import android.net.wifi.aware.SubscribeConfig;
 import android.net.wifi.aware.Characteristics;
+import android.net.wifi.aware.AwareResources;
 
 /**
  * Interface that WifiAwareService implements
@@ -36,6 +37,10 @@
     // Aware API
     boolean isUsageEnabled();
     Characteristics getCharacteristics();
+    AwareResources getAvailableAwareResources();
+    boolean isDeviceAttached();
+    void enableInstantCommunicationMode(in String callingPackage, boolean enable);
+    boolean isInstantCommunicationModeEnabled();
 
     // client API
     void connect(in IBinder binder, in String callingPackage, in String callingFeatureId,
diff --git a/framework/java/android/net/wifi/aware/WifiAwareManager.java b/framework/java/android/net/wifi/aware/WifiAwareManager.java
index c2ae17c..540bf2a 100644
--- a/framework/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/framework/java/android/net/wifi/aware/WifiAwareManager.java
@@ -22,6 +22,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -37,6 +38,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -151,6 +154,27 @@
      */
     public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
 
+    /** @hide */
+    @IntDef({
+            WIFI_AWARE_DISCOVERY_LOST_REASON_UNKNOWN,
+            WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DiscoveryLostReasonCode {
+    }
+
+    /**
+     * Reason code provided in {@link DiscoverySessionCallback#onServiceLost(PeerHandle, int)}
+     * indicating that the service was lost for unknown reason.
+     */
+    public static final int WIFI_AWARE_DISCOVERY_LOST_REASON_UNKNOWN = 0;
+
+    /**
+     * Reason code provided in {@link DiscoverySessionCallback#onServiceLost(PeerHandle, int)}
+     * indicating that the service advertised by the peer is no longer visible. This may be because
+     * the peer is out of range or because the peer stopped advertising this service.
+     */
+    public static final int WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE = 1;
+
     private final Context mContext;
     private final IWifiAwareManager mService;
 
@@ -179,12 +203,67 @@
     }
 
     /**
+     * Return the current status of the Aware service: whether ot not the device is already attached
+     * to an Aware cluster. To attach to an Aware cluster, please use
+     * {@link #attach(AttachCallback, Handler)} or
+     * {@link #attach(AttachCallback, IdentityChangedListener, Handler)}.
+     * @return A boolean indicating whether the device is attached to a cluster at this time (true)
+     *         or not (false).
+     */
+    public boolean isDeviceAttached() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mService.isDeviceAttached();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Enable the Wifi Aware Instant communication mode. If the device doesn't support this feature
+     * calling this API will result no action.
+     * @see Characteristics#isInstantCommunicationModeSupported()
+     * @param enable true for enable, false otherwise.
+     * @hide
+     */
+    @SystemApi
+    public void enableInstantCommunicationMode(boolean enable) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            mService.enableInstantCommunicationMode(mContext.getOpPackageName(), enable);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the current status of the Wifi Aware instant communication mode.
+     * If the device doesn't support this feature, return will always be false.
+     * @see Characteristics#isInstantCommunicationModeSupported()
+     * @return true if it is enabled, false otherwise.
+     */
+    public boolean isInstantCommunicationModeEnabled() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mService.isInstantCommunicationModeEnabled();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the characteristics of the Wi-Fi Aware interface: a set of parameters which specify
      * limitations on configurations, e.g. the maximum service name length.
      *
      * @return An object specifying configuration limitations of Aware.
      */
-    public Characteristics getCharacteristics() {
+    public @Nullable Characteristics getCharacteristics() {
         try {
             return mService.getCharacteristics();
         } catch (RemoteException e) {
@@ -193,6 +272,23 @@
     }
 
     /**
+     * Return the available resources of the Wi-Fi aware service: a set of parameters which specify
+     * limitations on service usage, e.g the number of data-paths which could be created..
+     *
+     * @return An object specifying the currently available resource of the Wi-Fi Aware service.
+     */
+    public @Nullable AwareResources getAvailableAwareResources() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mService.getAvailableAwareResources();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or
      * create connections to peers. The device will attach to an existing cluster if it can find
      * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results
@@ -587,6 +683,7 @@
         private static final int CALLBACK_MESSAGE_SEND_FAIL = 6;
         private static final int CALLBACK_MESSAGE_RECEIVED = 7;
         private static final int CALLBACK_MATCH_WITH_DISTANCE = 8;
+        private static final int CALLBACK_MATCH_EXPIRED = 9;
 
         private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message";
         private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2";
@@ -676,6 +773,14 @@
                             mOriginalCallback.onMessageReceived(new PeerHandle(msg.arg1),
                                     (byte[]) msg.obj);
                             break;
+                        case CALLBACK_MATCH_EXPIRED:
+                            if (!SdkLevel.isAtLeastS()) {
+                                break;
+                            }
+                            mOriginalCallback
+                                    .onServiceLost(new PeerHandle(msg.arg1),
+                                            WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE);
+                            break;
                     }
                 }
             };
@@ -746,6 +851,15 @@
             onMatchCommon(CALLBACK_MATCH_WITH_DISTANCE, peerId, serviceSpecificInfo, matchFilter,
                     distanceMm);
         }
+        @Override
+        public void onMatchExpired(int peerId) {
+            if (VDBG) {
+                Log.v(TAG, "onMatchExpired: peerId=" + peerId);
+            }
+            Message msg = mHandler.obtainMessage(CALLBACK_MATCH_EXPIRED);
+            msg.arg1 = peerId;
+            mHandler.sendMessage(msg);
+        }
 
         @Override
         public void onMessageSendSuccess(int messageId) {
diff --git a/framework/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/framework/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index d1d1780..006fbaa 100644
--- a/framework/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/framework/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -30,6 +30,8 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -412,6 +414,12 @@
     private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
 
     /**
+     * The subscription ID identifies the SIM card who provides this network configuration.
+     * See {@link SubscriptionInfo#getSubscriptionId()}
+     */
+    private int mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+    /**
      * Set the carrier ID associated with current configuration.
      * @param carrierId {@code mCarrierId}
      * @hide
@@ -430,6 +438,24 @@
     }
 
     /**
+     * Set the subscription ID associated with current configuration.
+     * @param subscriptionId {@code mSubscriptionId}
+     * @hide
+     */
+    public void setSubscriptionId(int subscriptionId) {
+        this.mSubscriptionId = subscriptionId;
+    }
+
+    /**
+     * Get the carrier ID associated with current configuration.
+     * @return {@code mSubscriptionId}
+     * @hide
+     */
+    public int getSubscriptionId() {
+        return mSubscriptionId;
+    }
+
+    /**
      * The auto-join configuration specifies whether or not the Passpoint Configuration is
      * considered for auto-connection. If true then yes, if false then it isn't considered as part
      * of auto-connection - but can still be manually connected to.
@@ -444,6 +470,32 @@
     private boolean mIsMacRandomizationEnabled = true;
 
     /**
+     * Whether this passpoint configuration should use enhanced MAC randomization.
+     */
+    private boolean mIsEnhancedMacRandomizationEnabled = false;
+
+
+    /**
+     * Indicate whether the network is oem paid or not. Networks are considered oem paid
+     * if the corresponding connection is only available to system apps.
+     * @hide
+     */
+    private boolean mIsOemPaid;
+
+    /**
+     * Indicate whether the network is oem private or not. Networks are considered oem private
+     * if the corresponding connection is only available to system apps.
+     * @hide
+     */
+    private boolean mIsOemPrivate;
+
+    /**
+     * Indicate whether or not the network is a carrier merged network.
+     * @hide
+     */
+    private boolean mIsCarrierMerged;
+
+    /**
      * Indicates if the end user has expressed an explicit opinion about the
      * meteredness of this network, such as through the Settings app.
      * This value is one of {@link #METERED_OVERRIDE_NONE}, {@link #METERED_OVERRIDE_METERED},
@@ -481,6 +533,20 @@
     }
 
     /**
+     * This setting is only applicable if MAC randomization is enabled.
+     * If set to true, the framework will periodically generate new MAC addresses for new
+     * connections.
+     * If set to false (the default), the framework will use the same locally generated MAC address
+     * for connections to this passpoint configuration.
+     * @param enabled true to use enhanced MAC randomization, false to use persistent MAC
+     *                randomization.
+     * @hide
+     */
+    public void setEnhancedMacRandomizationEnabled(boolean enabled) {
+        mIsEnhancedMacRandomizationEnabled = enabled;
+    }
+
+    /**
      * Sets the metered override setting for this Passpoint configuration.
      *
      * @param meteredOverride One of the values in {@link MeteredOverride}
@@ -531,6 +597,67 @@
     }
 
     /**
+     * When MAC randomization is enabled, this indicates whether enhanced MAC randomization or
+     * persistent MAC randomization will be used for connections to this Passpoint network.
+     * If true, the MAC address used for connections will periodically change. Otherwise, the same
+     * locally generated MAC will be used for all connections to this passpoint configuration.
+     *
+     * @return true for enhanced MAC randomization enabled. False for disabled.
+     * @hide
+     */
+    public boolean isEnhancedMacRandomizationEnabled() {
+        return mIsEnhancedMacRandomizationEnabled;
+    }
+
+    /**
+     * Set whether the network is oem paid or not.
+     * @hide
+     */
+    public void setOemPaid(boolean isOemPaid) {
+        mIsOemPaid = isOemPaid;
+    }
+
+    /**
+     * Get whether the network is oem paid or not.
+     * @hide
+     */
+    public boolean isOemPaid() {
+        return mIsOemPaid;
+    }
+
+    /**
+     * Set whether the network is oem private or not.
+     * @hide
+     */
+    public void setOemPrivate(boolean isOemPrivate) {
+        mIsOemPrivate = isOemPrivate;
+    }
+
+    /**
+     * Get whether the network is oem private or not.
+     * @hide
+     */
+    public boolean isOemPrivate() {
+        return mIsOemPrivate;
+    }
+
+    /**
+     * Set whether the network is carrier merged or not.
+     * @hide
+     */
+    public void setCarrierMerged(boolean isCarrierMerged) {
+        mIsCarrierMerged = isCarrierMerged;
+    }
+
+    /**
+     * Get whether the network is carrier merged or not.
+     * @hide
+     */
+    public boolean isCarrierMerged() {
+        return mIsCarrierMerged;
+    }
+
+    /**
      * Constructor for creating PasspointConfiguration with default values.
      */
     public PasspointConfiguration() {}
@@ -572,9 +699,14 @@
         mServiceFriendlyNames = source.mServiceFriendlyNames;
         mAaaServerTrustedNames = source.mAaaServerTrustedNames;
         mCarrierId = source.mCarrierId;
+        mSubscriptionId = source.mSubscriptionId;
         mIsAutojoinEnabled = source.mIsAutojoinEnabled;
         mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled;
+        mIsEnhancedMacRandomizationEnabled = source.mIsEnhancedMacRandomizationEnabled;
         mMeteredOverride = source.mMeteredOverride;
+        mIsCarrierMerged = source.mIsCarrierMerged;
+        mIsOemPaid = source.mIsOemPaid;
+        mIsOemPrivate = source.mIsOemPrivate;
     }
 
     @Override
@@ -606,7 +738,12 @@
         dest.writeInt(mCarrierId);
         dest.writeBoolean(mIsAutojoinEnabled);
         dest.writeBoolean(mIsMacRandomizationEnabled);
+        dest.writeBoolean(mIsEnhancedMacRandomizationEnabled);
         dest.writeInt(mMeteredOverride);
+        dest.writeInt(mSubscriptionId);
+        dest.writeBoolean(mIsCarrierMerged);
+        dest.writeBoolean(mIsOemPaid);
+        dest.writeBoolean(mIsOemPrivate);
     }
 
     @Override
@@ -637,8 +774,13 @@
                 && mUsageLimitDataLimit == that.mUsageLimitDataLimit
                 && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
                 && mCarrierId == that.mCarrierId
+                && mSubscriptionId == that.mSubscriptionId
+                && mIsOemPrivate == that.mIsOemPrivate
+                && mIsOemPaid == that.mIsOemPaid
+                && mIsCarrierMerged == that.mIsCarrierMerged
                 && mIsAutojoinEnabled == that.mIsAutojoinEnabled
                 && mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled
+                && mIsEnhancedMacRandomizationEnabled == that.mIsEnhancedMacRandomizationEnabled
                 && mMeteredOverride == that.mMeteredOverride
                 && (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
                 : mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
@@ -651,7 +793,8 @@
                 mSubscriptionExpirationTimeMillis, mUsageLimitUsageTimePeriodInMinutes,
                 mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
                 mServiceFriendlyNames, mCarrierId, mIsAutojoinEnabled, mIsMacRandomizationEnabled,
-                mMeteredOverride);
+                mIsEnhancedMacRandomizationEnabled, mMeteredOverride, mSubscriptionId,
+                mIsCarrierMerged, mIsOemPaid, mIsOemPrivate);
     }
 
     @Override
@@ -705,9 +848,14 @@
             builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames);
         }
         builder.append("CarrierId:" + mCarrierId);
+        builder.append("SubscriptionId:" + mSubscriptionId);
         builder.append("IsAutojoinEnabled:" + mIsAutojoinEnabled);
         builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled);
+        builder.append("mIsEnhancedMacRandomizationEnabled:" + mIsEnhancedMacRandomizationEnabled);
         builder.append("mMeteredOverride:" + mMeteredOverride);
+        builder.append("mIsCarrierMerged:" + mIsCarrierMerged);
+        builder.append("mIsOemPaid:" + mIsOemPaid);
+        builder.append("mIsOemPrivate" + mIsOemPrivate);
         return builder.toString();
     }
 
@@ -815,7 +963,13 @@
                 config.mCarrierId = in.readInt();
                 config.mIsAutojoinEnabled = in.readBoolean();
                 config.mIsMacRandomizationEnabled = in.readBoolean();
+                config.mIsEnhancedMacRandomizationEnabled = in.readBoolean();
                 config.mMeteredOverride = in.readInt();
+                config.mSubscriptionId = in.readInt();
+                config.mIsCarrierMerged = in.readBoolean();
+                config.mIsOemPaid = in.readBoolean();
+                config.mIsOemPrivate = in.readBoolean();
+
                 return config;
             }
 
diff --git a/framework/java/android/net/wifi/hotspot2/pps/HomeSp.java b/framework/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 8f34579..64aad61 100644
--- a/framework/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/framework/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -16,6 +16,8 @@
 
 package android.net.wifi.hotspot2.pps;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -23,6 +25,7 @@
 
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -139,16 +142,26 @@
      * (MO) tree for more detail.
      */
     private long[] mMatchAllOis = null;
+
     /**
-     * @hide
+     * Set a list of HomeOIs such that all OIs in the list must match an OI in the Roaming
+     * Consortium advertised by a hotspot operator. The list set by this API will have precedence
+     * over {@link #setMatchAnyOis(long[])}, meaning the list set in {@link #setMatchAnyOis(long[])}
+     * will only be used for matching if the list set by this API is null or empty.
+     *
+     * @param matchAllOis An array of longs containing the HomeOIs
      */
-    public void setMatchAllOis(long[] matchAllOis) {
+    public void setMatchAllOis(@Nullable long[] matchAllOis) {
         mMatchAllOis = matchAllOis;
     }
+
     /**
-     * @hide
+     * Get the list of HomeOIs such that all OIs in the list must match an OI in the Roaming
+     * Consortium advertised by a hotspot operator.
+     *
+     * @return An array of longs containing the HomeOIs
      */
-    public long[] getMatchAllOis() {
+    public @Nullable long[] getMatchAllOis() {
         return mMatchAllOis;
     }
 
@@ -159,23 +172,34 @@
      * of that Hotspot provider (e.g. successful authentication with such Hotspot
      * is possible).
      *
-     * {@link #mMatchAllOIs} will have precedence over this one, meaning this list will
-     * only be used for matching if {@link #mMatchAllOIs} is null or empty.
+     * The list set by {@link #setMatchAllOis(long[])} will have precedence over this one, meaning
+     * this list will only be used for matching if the list set by {@link #setMatchAllOis(long[])}
+     * is null or empty.
      *
      * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
      * (MO) tree for more detail.
      */
     private long[] mMatchAnyOis = null;
+
     /**
-     * @hide
+     * Set a list of HomeOIs such that any OI in the list matches an OI in the Roaming Consortium
+     * advertised by a hotspot operator. The list set by {@link #setMatchAllOis(long[])}
+     * will have precedence over this API, meaning this list will only be used for matching if the
+     * list set by {@link #setMatchAllOis(long[])} is null or empty.
+     *
+     * @param matchAnyOis An array of longs containing the HomeOIs
      */
-    public void setMatchAnyOis(long[] matchAnyOis) {
+    public void setMatchAnyOis(@Nullable long[] matchAnyOis) {
         mMatchAnyOis = matchAnyOis;
     }
+
     /**
-     * @hide
+     * Get a list of HomeOIs such that any OI in the list matches an OI in the Roaming Consortium
+     * advertised by a hotspot operator.
+     *
+     * @return An array of longs containing the HomeOIs
      */
-    public long[] getMatchAnyOis() {
+    public @Nullable long[] getMatchAnyOis() {
         return mMatchAnyOis;
     }
 
@@ -186,20 +210,58 @@
      * operator merges between the providers.
      */
     private String[] mOtherHomePartners = null;
+
     /**
+     * Set the list of FQDN (Fully Qualified Domain Name) of other Home partner providers.
+     *
+     * @param otherHomePartners Array of Strings containing the FQDNs of other Home partner
+     *                         providers
      * @hide
      */
-    public void setOtherHomePartners(String[] otherHomePartners) {
+    public void setOtherHomePartners(@Nullable String[] otherHomePartners) {
         mOtherHomePartners = otherHomePartners;
     }
+
     /**
+     * Set the list of FQDN (Fully Qualified Domain Name) of other Home partner providers.
+     *
+     * @param otherHomePartners Collection of Strings containing the FQDNs of other Home partner
+     *                         providers
+     */
+    public void setOtherHomePartnersList(@NonNull Collection<String> otherHomePartners) {
+        if (otherHomePartners == null) {
+            return;
+        }
+        mOtherHomePartners = otherHomePartners.toArray(new String[otherHomePartners.size()]);
+    }
+
+    /**
+     * Get the list of FQDN (Fully Qualified Domain Name) of other Home partner providers set in
+     * the profile.
+     *
+     * @return Array of Strings containing the FQDNs of other Home partner providers set in the
+     * profile
      * @hide
      */
-    public String[] getOtherHomePartners() {
+    public @Nullable String[] getOtherHomePartners() {
         return mOtherHomePartners;
     }
 
     /**
+     * Get the list of FQDN (Fully Qualified Domain Name) of other Home partner providers set in
+     * the profile.
+     *
+     * @return Collection of Strings containing the FQDNs of other Home partner providers set in the
+     * profile
+     */
+    public @NonNull Collection<String> getOtherHomePartnersList() {
+        if (mOtherHomePartners == null) {
+            return Collections.emptyList();
+        }
+        return Arrays.asList(mOtherHomePartners);
+    }
+
+    /**
      * List of Organization Identifiers (OIs) identifying a roaming consortium of
      * which this provider is a member.
      */
diff --git a/framework/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/framework/java/android/net/wifi/p2p/IWifiP2pManager.aidl
index bfdd45d..fd89d3b 100644
--- a/framework/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/framework/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -25,7 +25,7 @@
  */
 interface IWifiP2pManager
 {
-    Messenger getMessenger(in IBinder binder);
+    Messenger getMessenger(in IBinder binder, in String packageName);
     Messenger getP2pStateMachineMessenger();
     oneway void close(in IBinder binder);
     void setMiracastMode(int mode);
diff --git a/framework/java/android/net/wifi/p2p/WifiP2pManager.java b/framework/java/android/net/wifi/p2p/WifiP2pManager.java
index 5a27087..13ac7a0 100644
--- a/framework/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/framework/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1156,8 +1156,8 @@
      */
     public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
         Binder binder = new Binder();
-        Channel channel = initalizeChannel(srcContext, srcLooper, listener, getMessenger(binder),
-                binder);
+        Channel channel = initializeChannel(srcContext, srcLooper, listener,
+                getMessenger(binder, srcContext.getOpPackageName()), binder);
         return channel;
     }
 
@@ -1167,12 +1167,12 @@
      */
     public Channel initializeInternal(Context srcContext, Looper srcLooper,
                                       ChannelListener listener) {
-        return initalizeChannel(srcContext, srcLooper, listener, getP2pStateMachineMessenger(),
+        return initializeChannel(srcContext, srcLooper, listener, getP2pStateMachineMessenger(),
                 null);
     }
 
-    private Channel initalizeChannel(Context srcContext, Looper srcLooper, ChannelListener listener,
-                                     Messenger messenger, Binder binder) {
+    private Channel initializeChannel(Context srcContext, Looper srcLooper,
+            ChannelListener listener, Messenger messenger, Binder binder) {
         if (messenger == null) return null;
 
         Channel c = new Channel(srcContext, srcLooper, listener, binder, this);
@@ -1814,6 +1814,14 @@
         }
     }
 
+    private Messenger getMessenger(@NonNull Binder binder, @Nullable String packageName) {
+        try {
+            return mService.getMessenger(binder, packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Get a reference to WifiP2pService handler. This is used to establish
      * an AsyncChannel communication with WifiService
@@ -1824,11 +1832,8 @@
      * @hide
      */
     public Messenger getMessenger(Binder binder) {
-        try {
-            return mService.getMessenger(binder);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        // No way to determine package name in this case.
+        return getMessenger(binder, null);
     }
 
     /**
diff --git a/framework/java/android/net/wifi/rtt/RangingRequest.java b/framework/java/android/net/wifi/rtt/RangingRequest.java
index 318efa6..04dfcf2 100644
--- a/framework/java/android/net/wifi/rtt/RangingRequest.java
+++ b/framework/java/android/net/wifi/rtt/RangingRequest.java
@@ -30,8 +30,11 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.StringJoiner;
 
 /**
@@ -46,6 +49,9 @@
  */
 public final class RangingRequest implements Parcelable {
     private static final int MAX_PEERS = 10;
+    private static final int DEFAULT_RTT_BURST_SIZE = 8;
+    private static final int MIN_RTT_BURST_SIZE = 2;
+    private static final int MAX_RTT_BURST_SIZE = 17;
 
     /**
      * Returns the maximum number of peers to range which can be specified in a single {@code
@@ -59,12 +65,80 @@
         return MAX_PEERS;
     }
 
+    /**
+     * Returns the default RTT burst size used to determine the average range.
+     *
+     * @return the RTT burst size used by default
+     */
+    public static int getDefaultRttBurstSize() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return DEFAULT_RTT_BURST_SIZE;
+    }
+
+    /**
+     * Returns the minimum RTT burst size that can be used to determine a average range.
+     *
+     * @return the minimum RTT burst size that can be used
+     */
+    public static int getMinRttBurstSize() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return MIN_RTT_BURST_SIZE;
+    }
+
+    /**
+     * Returns the minimum RTT burst size that can be used to determine a average range.
+     *
+     * @return the maximum RTT burst size that can be used
+     */
+    public static int getMaxRttBurstSize() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return MAX_RTT_BURST_SIZE;
+    }
+
     /** @hide */
     public final List<ResponderConfig> mRttPeers;
 
     /** @hide */
-    private RangingRequest(List<ResponderConfig> rttPeers) {
+    public final int mRttBurstSize;
+
+    /** @hide */
+    private RangingRequest(List<ResponderConfig> rttPeers, int rttBurstSize) {
         mRttPeers = rttPeers;
+        mRttBurstSize = rttBurstSize;
+    }
+
+    /**
+     * Returns the list of RTT capable peers.
+     *
+     * @return the list of RTT capable peers in a common system representation
+     *
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    public List<ResponderConfig> getRttPeers() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mRttPeers;
+    }
+
+    /**
+     * Returns the RTT burst size used to determine the average range.
+     *
+     * @return the RTT burst size used
+     */
+    public int getRttBurstSize() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return mRttBurstSize;
     }
 
     @Override
@@ -75,6 +149,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeList(mRttPeers);
+        dest.writeInt(mRttBurstSize);
     }
 
     public static final @android.annotation.NonNull Creator<RangingRequest> CREATOR = new Creator<RangingRequest>() {
@@ -85,7 +160,7 @@
 
         @Override
         public RangingRequest createFromParcel(Parcel in) {
-            return new RangingRequest(in.readArrayList(null));
+            return new RangingRequest(in.readArrayList(null), in.readInt());
         }
     };
 
@@ -105,12 +180,20 @@
             throw new IllegalArgumentException(
                     "Ranging to too many peers requested. Use getMaxPeers() API to get limit.");
         }
-
         for (ResponderConfig peer: mRttPeers) {
             if (!peer.isValid(awareSupported)) {
                 throw new IllegalArgumentException("Invalid Responder specification");
             }
         }
+        if (SdkLevel.isAtLeastS()) {
+            if (mRttBurstSize < getMinRttBurstSize() || mRttBurstSize > getMaxRttBurstSize()) {
+                throw new IllegalArgumentException("RTT burst size is out of range");
+            }
+        } else {
+            if (mRttBurstSize != DEFAULT_RTT_BURST_SIZE) {
+                throw new IllegalArgumentException("RTT burst size is not the default value");
+            }
+        }
     }
 
     /**
@@ -118,6 +201,32 @@
      */
     public static final class Builder {
         private List<ResponderConfig> mRttPeers = new ArrayList<>();
+        private int mRttBurstSize = DEFAULT_RTT_BURST_SIZE;
+
+        /**
+         * Set the RTT Burst size for the ranging request.
+         * <p>
+         * If not set, the default RTT burst size given by
+         * {@link #getDefaultRttBurstSize()} is used to determine the default value.
+         * If set, the value must be in the range {@link #getMinRttBurstSize()} and
+         * {@link #getMaxRttBurstSize()} inclusively, or a
+         * {@link java.lang.IllegalArgumentException} will be thrown.
+         *
+         * @param rttBurstSize The number of FTM packets used to estimate a range.
+         * @return The builder to facilitate chaining
+         * {@code builder.setXXX(..).setXXX(..)}.
+         */
+        @NonNull
+        public Builder setRttBurstSize(int rttBurstSize) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
+            if (rttBurstSize < MIN_RTT_BURST_SIZE || rttBurstSize > MAX_RTT_BURST_SIZE) {
+                throw new IllegalArgumentException("RTT burst size out of range.");
+            }
+            mRttBurstSize = rttBurstSize;
+            return this;
+        }
 
         /**
          * Add the device specified by the {@link ScanResult} to the list of devices with
@@ -241,7 +350,7 @@
          * builder.
          */
         public RangingRequest build() {
-            return new RangingRequest(mRttPeers);
+            return new RangingRequest(mRttPeers, mRttBurstSize);
         }
     }
 
@@ -257,11 +366,13 @@
 
         RangingRequest lhs = (RangingRequest) o;
 
-        return mRttPeers.size() == lhs.mRttPeers.size() && mRttPeers.containsAll(lhs.mRttPeers);
+        return mRttPeers.size() == lhs.mRttPeers.size()
+                && mRttPeers.containsAll(lhs.mRttPeers)
+                && mRttBurstSize == lhs.mRttBurstSize;
     }
 
     @Override
     public int hashCode() {
-        return mRttPeers.hashCode();
+        return Objects.hash(mRttPeers, mRttBurstSize);
     }
 }
diff --git a/framework/tests/Android.bp b/framework/tests/Android.bp
index 0e58740..c0be244 100644
--- a/framework/tests/Android.bp
+++ b/framework/tests/Android.bp
@@ -20,6 +20,9 @@
 
     defaults: ["framework-wifi-test-defaults"],
 
+    min_sdk_version: "30",
+    target_sdk_version: "30",
+
     srcs: ["**/*.java"],
 
     jacoco: {
@@ -46,7 +49,7 @@
     ],
 
     test_suites: [
-        "device-tests",
+        "general-tests",
         "mts",
     ],
 
diff --git a/framework/tests/AndroidManifest.xml b/framework/tests/AndroidManifest.xml
index b6c38bc..8fcf78f 100644
--- a/framework/tests/AndroidManifest.xml
+++ b/framework/tests/AndroidManifest.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
   ~ Copyright (C) 2016 The Android Open Source Project
   ~
@@ -17,22 +16,23 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.net.wifi.test">
+     package="android.net.wifi.test">
 
     <application>
-        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="android.test.runner"/>
         <activity android:label="WifiTestDummyLabel"
-                  android:name="WifiTestDummyName">
+             android:name="WifiTestDummyName"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
+                <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="android.net.wifi.test"
-        android:label="Frameworks Wifi API Tests">
+         android:targetPackage="android.net.wifi.test"
+         android:label="Frameworks Wifi API Tests">
     </instrumentation>
 
 </manifest>
diff --git a/framework/tests/AndroidTest.xml b/framework/tests/AndroidTest.xml
index 34e2e3a..2cdaddb 100644
--- a/framework/tests/AndroidTest.xml
+++ b/framework/tests/AndroidTest.xml
@@ -20,6 +20,8 @@
 
     <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="FrameworksWifiApiTests" />
+    <option name="config-descriptor:metadata" key="mainline-param"
+            value="com.google.android.wifi.apex" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.net.wifi.test" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/framework/tests/src/android/net/wifi/CoexUnsafeChannelTest.java b/framework/tests/src/android/net/wifi/CoexUnsafeChannelTest.java
new file mode 100644
index 0000000..320f25e
--- /dev/null
+++ b/framework/tests/src/android/net/wifi/CoexUnsafeChannelTest.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;
+
+import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.CoexUnsafeChannel}.
+ */
+@SmallTest
+public class CoexUnsafeChannelTest {
+    /**
+     * Verifies {@link CoexUnsafeChannel#isPowerCapAvailable()} returns false if no cap is set.
+     */
+    @Test
+    public void testIsPowerCapAvailable_noPowerCap_returnsFalse() {
+        CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+        assertThat(unsafeChannel.isPowerCapAvailable()).isFalse();
+    }
+
+    /**
+     * Verifies {@link CoexUnsafeChannel#isPowerCapAvailable()} returns true if a cap is set, and
+     * {@link CoexUnsafeChannel#getPowerCapDbm()} returns the set value.
+     */
+    @Test
+    public void testIsPowerCapAvailable_powerCapSet_returnsTrue() {
+        final int powerCapDbm = -50;
+        CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+        unsafeChannel.setPowerCapDbm(powerCapDbm);
+
+        assertThat(unsafeChannel.isPowerCapAvailable()).isTrue();
+        assertThat(unsafeChannel.getPowerCapDbm()).isEqualTo(powerCapDbm);
+    }
+
+    /**
+     * Verifies {@link CoexUnsafeChannel#getPowerCapDbm()} throws an IllegalStateException if
+     * {@link CoexUnsafeChannel#isPowerCapAvailable()} is {@code false}.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testGetPowerCap_powerCapUnavailable_throwsException() {
+        CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+        unsafeChannel.getPowerCapDbm();
+    }
+
+    /**
+     * Verify parcel read/write for CoexUnsafeChannel with or without power cap.
+     */
+    @Test
+    public void testParcelReadWrite_withOrWithoutCap_readEqualsWritten() throws Exception {
+        CoexUnsafeChannel writeUnsafeChannelNoCap =
+                new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+        CoexUnsafeChannel writeUnsafeChannelCapped =
+                new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6, -50);
+
+        CoexUnsafeChannel readUnsafeChannelNoCap = parcelReadWrite(writeUnsafeChannelNoCap);
+        CoexUnsafeChannel readUnsafeChannelCapped = parcelReadWrite(writeUnsafeChannelCapped);
+
+        assertThat(writeUnsafeChannelNoCap).isEqualTo(readUnsafeChannelNoCap);
+        assertThat(writeUnsafeChannelCapped).isEqualTo(readUnsafeChannelCapped);
+    }
+
+    /**
+     * Write the provided {@link CoexUnsafeChannel} to a parcel and deserialize it.
+     */
+    private static CoexUnsafeChannel parcelReadWrite(CoexUnsafeChannel writeResult)
+            throws Exception {
+        Parcel parcel = Parcel.obtain();
+        writeResult.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        return CoexUnsafeChannel.CREATOR.createFromParcel(parcel);
+    }
+}
diff --git a/framework/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java b/framework/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
index b101414..cf37b78 100644
--- a/framework/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
+++ b/framework/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.NonNull;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
@@ -52,6 +53,11 @@
             mOnFailureR1EventReceived = true;
             mLastCode = code;
         }
+
+        @Override
+        public void onBootstrapUriGenerated(@NonNull String uri) {
+
+        }
     };
     private boolean mOnFailureR1EventReceived;
     private int mLastCode;
diff --git a/framework/tests/src/android/net/wifi/ScanResultTest.java b/framework/tests/src/android/net/wifi/ScanResultTest.java
index f1ec5e8..59b88a7 100644
--- a/framework/tests/src/android/net/wifi/ScanResultTest.java
+++ b/framework/tests/src/android/net/wifi/ScanResultTest.java
@@ -44,6 +44,7 @@
     public static final long TEST_TSF = 04660l;
     public static final @WifiAnnotations.WifiStandard int TEST_WIFI_STANDARD =
             ScanResult.WIFI_STANDARD_11AC;
+    public static final String TEST_IFACE_NAME = "test_ifname";
 
     /**
      * Frequency to channel map. This include some frequencies used outside the US.
@@ -220,7 +221,7 @@
                 + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
                 + "standard: 11ac, "
                 + "80211mcResponder: is not supported, "
-                + "Radio Chain Infos: null", scanResult.toString());
+                + "Radio Chain Infos: null, interface name: test_ifname", scanResult.toString());
     }
 
     /**
@@ -243,7 +244,8 @@
                 + "standard: 11ac, "
                 + "80211mcResponder: is not supported, "
                 + "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, "
-                + "RadioChainInfo: id=1, level=-54]", scanResult.toString());
+                + "RadioChainInfo: id=1, level=-54], interface name: test_ifname",
+                scanResult.toString());
     }
 
     /**
@@ -284,6 +286,8 @@
         result.frequency = TEST_FREQUENCY;
         result.timestamp = TEST_TSF;
         result.setWifiStandard(TEST_WIFI_STANDARD);
+        result.ifaceName = TEST_IFACE_NAME;
+
         return result;
     }
 
diff --git a/framework/tests/src/android/net/wifi/SecurityParamsTest.java b/framework/tests/src/android/net/wifi/SecurityParamsTest.java
new file mode 100644
index 0000000..c586ded
--- /dev/null
+++ b/framework/tests/src/android/net/wifi/SecurityParamsTest.java
@@ -0,0 +1,556 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.GroupCipher;
+import android.net.wifi.WifiConfiguration.GroupMgmtCipher;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiConfiguration.PairwiseCipher;
+import android.net.wifi.WifiConfiguration.Protocol;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+import java.util.BitSet;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiInfo}.
+ */
+@SmallTest
+public class SecurityParamsTest {
+
+    private void verifySecurityParams(SecurityParams params,
+            int expectedSecurityType,
+            int[] expectedAllowedKeyManagement,
+            int[] expectedAllowedProtocols,
+            int[] expectedAllowedAuthAlgorithms,
+            int[] expectedAllowedPairwiseCiphers,
+            int[] expectedAllowedGroupCiphers,
+            boolean expectedRequirePmf) {
+        assertTrue(params.isSecurityType(expectedSecurityType));
+        assertEquals(expectedSecurityType, params.getSecurityType());
+        for (int b: expectedAllowedKeyManagement) {
+            assertTrue(params.getAllowedKeyManagement().get(b));
+        }
+        for (int b: expectedAllowedProtocols) {
+            assertTrue(params.getAllowedProtocols().get(b));
+        }
+        for (int b: expectedAllowedAuthAlgorithms) {
+            assertTrue(params.getAllowedAuthAlgorithms().get(b));
+        }
+        for (int b: expectedAllowedPairwiseCiphers) {
+            assertTrue(params.getAllowedPairwiseCiphers().get(b));
+        }
+        for (int b: expectedAllowedGroupCiphers) {
+            assertTrue(params.getAllowedGroupCiphers().get(b));
+        }
+        assertEquals(expectedRequirePmf, params.isRequirePmf());
+    }
+
+    /** Verify the security params created by security type. */
+    @Test
+    public void testSecurityTypeCreator() throws Exception {
+        int[] securityTypes = new int[] {
+                WifiConfiguration.SECURITY_TYPE_WAPI_CERT,
+                WifiConfiguration.SECURITY_TYPE_WAPI_PSK,
+                WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
+                WifiConfiguration.SECURITY_TYPE_OWE,
+                WifiConfiguration.SECURITY_TYPE_SAE,
+                WifiConfiguration.SECURITY_TYPE_OSEN,
+                WifiConfiguration.SECURITY_TYPE_EAP,
+                WifiConfiguration.SECURITY_TYPE_PSK,
+                WifiConfiguration.SECURITY_TYPE_OPEN,
+                WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2,
+                WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3,
+        };
+
+        for (int type: securityTypes) {
+            assertEquals(type,
+                    SecurityParams.createSecurityParamsBySecurityType(type).getSecurityType());
+        }
+    }
+
+    /** Verify EAP params creator. */
+    @Test
+    public void testEapCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
+        int[] expectedAllowedProtocols = new int[] {};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {};
+        int[] expectedAllowedGroupCiphers = new int[] {};
+        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify Passpoint R1/R2 params creator. */
+    @Test
+    public void testEapPasspointR1R2Creator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
+        int[] expectedAllowedProtocols = new int[] {};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {};
+        int[] expectedAllowedGroupCiphers = new int[] {};
+        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify Passpoint R3 params creator. */
+    @Test
+    public void testEapPasspointR3Creator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
+        int[] expectedAllowedProtocols = new int[] {};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {};
+        int[] expectedAllowedGroupCiphers = new int[] {};
+        boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify Enhanced Open params creator. */
+    @Test
+    public void testEnhancedOpenCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OWE;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.OWE};
+        int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {
+                PairwiseCipher.CCMP, PairwiseCipher.GCMP_128, PairwiseCipher.GCMP_256};
+        int[] expectedAllowedGroupCiphers = new int[] {
+                GroupCipher.CCMP, GroupCipher.GCMP_128, GroupCipher.GCMP_256};
+        boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify Open params creator. */
+    @Test
+    public void testOpenCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OPEN;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.NONE};
+        int[] expectedAllowedProtocols = new int[] {};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {};
+        int[] expectedAllowedGroupCiphers = new int[] {};
+        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify OSEN params creator. */
+    @Test
+    public void testOsenCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OSEN;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.OSEN};
+        int[] expectedAllowedProtocols = new int[] {Protocol.OSEN};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {};
+        int[] expectedAllowedGroupCiphers = new int[] {};
+        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify WAPI CERT params creator. */
+    @Test
+    public void testWapiCertCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WAPI_CERT};
+        int[] expectedAllowedProtocols = new int[] {Protocol.WAPI};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {PairwiseCipher.SMS4};
+        int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.SMS4};
+        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify WAPI PSK params creator. */
+    @Test
+    public void testWapiPskCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WAPI_PSK};
+        int[] expectedAllowedProtocols = new int[] {Protocol.WAPI};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {PairwiseCipher.SMS4};
+        int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.SMS4};
+        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify WEP params creator. */
+    @Test
+    public void testWepCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WEP;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.NONE};
+        int[] expectedAllowedProtocols = new int[] {};
+        int[] expectedAllowedAuthAlgorithms = new int[] {AuthAlgorithm.OPEN, AuthAlgorithm.SHARED};
+        int[] expectedAllowedPairwiseCiphers = new int[] {};
+        int[] expectedAllowedGroupCiphers = new int[] {};
+        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify WPA3 Enterprise 192-bit params creator. */
+    @Test
+    public void testWpa3Enterprise192BitCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
+        int[] expectedAllowedKeyManagement = new int[] {
+                KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X, KeyMgmt.SUITE_B_192};
+        int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {
+                PairwiseCipher.GCMP_128, PairwiseCipher.GCMP_256};
+        int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.GCMP_128, GroupCipher.GCMP_256};
+        boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+
+        assertTrue(p.getAllowedGroupManagementCiphers().get(GroupMgmtCipher.BIP_GMAC_256));
+    }
+
+    /** Verify WPA3 Enterprise params creator. */
+    @Test
+    public void testWpa3EnterpriseCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
+        int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {
+                PairwiseCipher.CCMP, PairwiseCipher.GCMP_256};
+        int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.CCMP, GroupCipher.GCMP_256};
+        boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify WPA3 Personal params creator. */
+    @Test
+    public void testWpa3PersonalCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_SAE;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.SAE};
+        int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {
+                PairwiseCipher.CCMP, PairwiseCipher.GCMP_128, PairwiseCipher.GCMP_256};
+        int[] expectedAllowedGroupCiphers = new int[] {
+                GroupCipher.CCMP, GroupCipher.GCMP_128, GroupCipher.GCMP_256};
+        boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify WPA2 Personal EAP params creator. */
+    @Test
+    public void testWpaWpa2PersonalCreator() throws Exception {
+        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PSK;
+        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_PSK};
+        int[] expectedAllowedProtocols = new int[] {};
+        int[] expectedAllowedAuthAlgorithms = new int[] {};
+        int[] expectedAllowedPairwiseCiphers = new int[] {};
+        int[] expectedAllowedGroupCiphers = new int[] {};
+        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
+        verifySecurityParams(p, expectedSecurityType,
+                expectedAllowedKeyManagement, expectedAllowedProtocols,
+                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
+                expectedAllowedGroupCiphers, expectedRequirePmf);
+    }
+
+    /** Verify setter/getter methods */
+    @Test
+    public void testCommonSetterGetter() throws Exception {
+        SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_PSK);
+
+        // PSK setting
+        BitSet allowedKeyManagement = new BitSet();
+        allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+
+        BitSet allowedProtocols = new BitSet();
+        allowedProtocols.set(Protocol.RSN);
+        allowedProtocols.set(Protocol.WPA);
+
+        BitSet allowedPairwiseCiphers = new BitSet();
+        allowedPairwiseCiphers.set(PairwiseCipher.CCMP);
+        allowedPairwiseCiphers.set(PairwiseCipher.TKIP);
+
+        BitSet allowedGroupCiphers = new BitSet();
+        allowedGroupCiphers.set(GroupCipher.CCMP);
+        allowedGroupCiphers.set(GroupCipher.TKIP);
+        allowedGroupCiphers.set(GroupCipher.WEP40);
+        allowedGroupCiphers.set(GroupCipher.WEP104);
+
+        assertEquals(allowedKeyManagement, params.getAllowedKeyManagement());
+        assertTrue(params.getAllowedKeyManagement().get(KeyMgmt.WPA_PSK));
+
+        assertEquals(allowedProtocols, params.getAllowedProtocols());
+        assertTrue(params.getAllowedProtocols().get(Protocol.RSN));
+        assertTrue(params.getAllowedProtocols().get(Protocol.WPA));
+
+        assertEquals(allowedPairwiseCiphers, params.getAllowedPairwiseCiphers());
+        assertTrue(params.getAllowedPairwiseCiphers().get(PairwiseCipher.CCMP));
+        assertTrue(params.getAllowedPairwiseCiphers().get(PairwiseCipher.TKIP));
+
+        assertEquals(allowedGroupCiphers, params.getAllowedGroupCiphers());
+        assertTrue(params.getAllowedGroupCiphers().get(GroupCipher.CCMP));
+        assertTrue(params.getAllowedGroupCiphers().get(GroupCipher.TKIP));
+        assertTrue(params.getAllowedGroupCiphers().get(GroupCipher.WEP40));
+        assertTrue(params.getAllowedGroupCiphers().get(GroupCipher.WEP104));
+
+        params.setEnabled(false);
+        assertFalse(params.isEnabled());
+    }
+
+    /** Verify SAE-specific methods */
+    @Test
+    public void testSaeMethods() throws Exception {
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+
+        assertFalse(p.isAddedByAutoUpgrade());
+        p.setIsAddedByAutoUpgrade(true);
+        assertTrue(p.isAddedByAutoUpgrade());
+
+        assertFalse(p.isSaeH2eOnlyMode());
+        p.enableSaeH2eOnlyMode(true);
+        assertTrue(p.isSaeH2eOnlyMode());
+
+        assertFalse(p.isSaePkOnlyMode());
+        p.enableSaePkOnlyMode(true);
+        assertTrue(p.isSaePkOnlyMode());
+    }
+
+    /** Verify copy constructor. */
+    @Test
+    public void testCopyConstructor() throws Exception {
+        SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_PSK);
+        params.setEnabled(false);
+        params.setIsAddedByAutoUpgrade(true);
+
+        SecurityParams copiedParams = new SecurityParams(params);
+
+        assertTrue(params.isSameSecurityType(copiedParams));
+        assertEquals(params.getAllowedKeyManagement(), copiedParams.getAllowedKeyManagement());
+        assertEquals(params.getAllowedProtocols(), copiedParams.getAllowedProtocols());
+        assertEquals(params.getAllowedAuthAlgorithms(), copiedParams.getAllowedAuthAlgorithms());
+        assertEquals(params.getAllowedPairwiseCiphers(), copiedParams.getAllowedPairwiseCiphers());
+        assertEquals(params.getAllowedGroupCiphers(), copiedParams.getAllowedGroupCiphers());
+        assertEquals(params.getAllowedGroupManagementCiphers(),
+                copiedParams.getAllowedGroupManagementCiphers());
+        assertEquals(params.getAllowedSuiteBCiphers(), copiedParams.getAllowedSuiteBCiphers());
+        assertEquals(params.isRequirePmf(), copiedParams.isRequirePmf());
+        assertEquals(params.isEnabled(), copiedParams.isEnabled());
+        assertEquals(params.isSaeH2eOnlyMode(), copiedParams.isSaeH2eOnlyMode());
+        assertEquals(params.isSaePkOnlyMode(), copiedParams.isSaePkOnlyMode());
+        assertEquals(params.isAddedByAutoUpgrade(), copiedParams.isAddedByAutoUpgrade());
+    }
+
+    /** Check that two params are equal if and only if their types are the same. */
+    @Test
+    public void testEquals() {
+        SecurityParams saeParams1 = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+        SecurityParams saeParams2 = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+        SecurityParams pskParams = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_PSK);
+        assertEquals(saeParams1, saeParams2);
+        assertNotEquals(saeParams1, pskParams);
+    }
+
+    /** Check that hash values are the same if and only if their types are the same. */
+    @Test
+    public void testHashCode() {
+        SecurityParams saeParams1 = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+        SecurityParams saeParams2 = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+        SecurityParams pskParams = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_PSK);
+        assertEquals(saeParams1.hashCode(), saeParams2.hashCode());
+        assertNotEquals(saeParams1.hashCode(), pskParams.hashCode());
+    }
+
+    /** Verify open network check */
+    @Test
+    public void testIsOpenNetwork() {
+        SecurityParams[] openSecurityParams = new SecurityParams[] {
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OWE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OPEN),
+        };
+        for (SecurityParams p: openSecurityParams) {
+            assertTrue(p.isOpenSecurityType());
+        }
+
+        SecurityParams[] nonOpenSecurityParams = new SecurityParams[] {
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OSEN),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WAPI_PSK),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WAPI_CERT),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WEP),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_SAE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PSK),
+        };
+        for (SecurityParams p: nonOpenSecurityParams) {
+            assertFalse(p.isOpenSecurityType());
+        }
+    }
+
+    /** Verify enterprise network check */
+    @Test
+    public void testIsEnterpriseNetwork() {
+        SecurityParams[] enterpriseSecurityParams = new SecurityParams[] {
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WAPI_CERT),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE),
+        };
+        for (SecurityParams p: enterpriseSecurityParams) {
+            assertTrue(p.isEnterpriseSecurityType());
+        }
+
+        SecurityParams[] nonEnterpriseSecurityParams = new SecurityParams[] {
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OWE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OPEN),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OSEN),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WAPI_PSK),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WEP),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_SAE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PSK),
+        };
+        for (SecurityParams p: nonEnterpriseSecurityParams) {
+            assertFalse(p.isEnterpriseSecurityType());
+        }
+    }
+
+    /** Check that parcel marshalling/unmarshalling works */
+    @Test
+    public void testParcelMethods() {
+        SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+
+        Parcel parcelW = Parcel.obtain();
+        params.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+
+        SecurityParams reParams = SecurityParams.createFromParcel(parcelR);
+        assertEquals(params, reParams);
+    }
+}
diff --git a/framework/tests/src/android/net/wifi/SoftApCapabilityTest.java b/framework/tests/src/android/net/wifi/SoftApCapabilityTest.java
index 73b501a..9e3b022 100644
--- a/framework/tests/src/android/net/wifi/SoftApCapabilityTest.java
+++ b/framework/tests/src/android/net/wifi/SoftApCapabilityTest.java
@@ -16,12 +16,15 @@
 
 package android.net.wifi;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
 import android.os.Parcel;
 
-import static org.junit.Assert.assertEquals;
-
 import androidx.test.filters.SmallTest;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import org.junit.Test;
 
 /**
@@ -37,8 +40,14 @@
     public void testCopyOperator() throws Exception {
         long testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
                 | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
+        int[] testSupported2Glist = {1, 2, 3, 4};
+        int[] testSupported5Glist = {36, 149};
+        int[] testSupported60Glist = {1, 2};
         SoftApCapability capability = new SoftApCapability(testSoftApFeature);
         capability.setMaxSupportedClients(10);
+        capability.setSupportedChannelList(SoftApConfiguration.BAND_2GHZ, testSupported2Glist);
+        capability.setSupportedChannelList(SoftApConfiguration.BAND_5GHZ, testSupported5Glist);
+        capability.setSupportedChannelList(SoftApConfiguration.BAND_60GHZ, testSupported60Glist);
 
         SoftApCapability copiedCapability = new SoftApCapability(capability);
 
@@ -55,6 +64,13 @@
                 | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
         SoftApCapability capability = new SoftApCapability(testSoftApFeature);
         capability.setMaxSupportedClients(10);
+        int[] testSupported2Glist = {1, 2, 3, 4};
+        int[] testSupported5Glist = {36, 149};
+        int[] testSupported60Glist = {1, 2};
+
+        capability.setSupportedChannelList(SoftApConfiguration.BAND_2GHZ, testSupported2Glist);
+        capability.setSupportedChannelList(SoftApConfiguration.BAND_5GHZ, testSupported5Glist);
+        capability.setSupportedChannelList(SoftApConfiguration.BAND_60GHZ, testSupported60Glist);
 
         Parcel parcelW = Parcel.obtain();
         capability.writeToParcel(parcelW, 0);
@@ -70,4 +86,24 @@
         assertEquals(capability.hashCode(), fromParcel.hashCode());
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testSetSupportedChannelListWithInvalidBand() {
+        long testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
+                | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
+        SoftApCapability capability = new SoftApCapability(testSoftApFeature);
+        capability.setSupportedChannelList(
+                SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ, new int[0]);
+
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetSupportedChannelListWithInvalidBand() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        long testSoftApFeature = SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT
+                | SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD;
+        SoftApCapability capability = new SoftApCapability(testSoftApFeature);
+        capability.getSupportedChannelList(
+                SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ);
+    }
 }
diff --git a/framework/tests/src/android/net/wifi/SoftApConfigurationTest.java b/framework/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 2d7e535..a609a12 100644
--- a/framework/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/framework/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -19,21 +19,28 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.net.MacAddress;
 import android.os.Parcel;
+import android.util.SparseIntArray;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 
 @SmallTest
 public class SoftApConfigurationTest {
     private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789";
+    private static final String TEST_BSSID = "aa:22:33:aa:bb:cc";
 
     private SoftApConfiguration parcelUnparcel(SoftApConfiguration configIn) {
         Parcel parcel = Parcel.obtain();
@@ -66,18 +73,23 @@
 
     @Test
     public void testBasicSettings() {
+        MacAddress testBssid = MacAddress.fromString(TEST_BSSID);
         SoftApConfiguration original = new SoftApConfiguration.Builder()
                 .setSsid("ssid")
-                .setBssid(MacAddress.fromString("11:22:33:44:55:66"))
+                .setBssid(testBssid)
                 .build();
         assertThat(original.getSsid()).isEqualTo("ssid");
-        assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
+        assertThat(original.getBssid()).isEqualTo(testBssid);
         assertThat(original.getPassphrase()).isNull();
         assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
         assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
         assertThat(original.getChannel()).isEqualTo(0);
         assertThat(original.isHiddenSsid()).isEqualTo(false);
         assertThat(original.getMaxNumberOfClients()).isEqualTo(0);
+        if (SdkLevel.isAtLeastS()) {
+            assertThat(original.getMacRandomizationSetting())
+                    .isEqualTo(SoftApConfiguration.RANDOMIZATION_PERSISTENT);
+        }
 
         SoftApConfiguration unparceled = parcelUnparcel(original);
         assertThat(unparceled).isNotSameInstanceAs(original);
@@ -120,7 +132,7 @@
         List<MacAddress> testAllowedClientList = new ArrayList<>();
         testBlockedClientList.add(MacAddress.fromString("11:22:33:44:55:66"));
         testAllowedClientList.add(MacAddress.fromString("aa:bb:cc:dd:ee:ff"));
-        SoftApConfiguration original = new SoftApConfiguration.Builder()
+        SoftApConfiguration.Builder originalBuilder = new SoftApConfiguration.Builder()
                 .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
                 .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                 .setHiddenSsid(true)
@@ -129,8 +141,11 @@
                 .setShutdownTimeoutMillis(500000)
                 .setClientControlByUserEnabled(true)
                 .setBlockedClientList(testBlockedClientList)
-                .setAllowedClientList(testAllowedClientList)
-                .build();
+                .setAllowedClientList(testAllowedClientList);
+        if (SdkLevel.isAtLeastS()) {
+            originalBuilder.setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE);
+        }
+        SoftApConfiguration original = originalBuilder.build();
         assertThat(original.getPassphrase()).isEqualTo("secretsecret");
         assertThat(original.getSecurityType()).isEqualTo(
                 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
@@ -143,6 +158,10 @@
         assertThat(original.isClientControlByUserEnabled()).isEqualTo(true);
         assertThat(original.getBlockedClientList()).isEqualTo(testBlockedClientList);
         assertThat(original.getAllowedClientList()).isEqualTo(testAllowedClientList);
+        if (SdkLevel.isAtLeastS()) {
+            assertThat(original.getMacRandomizationSetting())
+                    .isEqualTo(SoftApConfiguration.RANDOMIZATION_NONE);
+        }
 
         SoftApConfiguration unparceled = parcelUnparcel(original);
         assertThat(unparceled).isNotSameInstanceAs(original);
@@ -209,6 +228,20 @@
     }
 
     @Test(expected = IllegalArgumentException.class)
+    public void testInvalidBroadcastBssid() {
+        SoftApConfiguration original = new SoftApConfiguration.Builder()
+                .setBssid(MacAddress.BROADCAST_ADDRESS)
+                .build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalidMulticastBssid() {
+        SoftApConfiguration original = new SoftApConfiguration.Builder()
+                .setBssid(MacAddress.fromString("01:aa:bb:cc:dd:ee"))
+                .build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
     public void testInvalidShortPasswordLengthForWpa2() {
         SoftApConfiguration original = new SoftApConfiguration.Builder()
                 .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
@@ -336,4 +369,164 @@
                 .isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
         assertThat(wifiConfig_sae_transition.preSharedKey).isEqualTo("secretsecret");
     }
+
+    @Test
+    public void testDualBands() {
+        assumeTrue(SdkLevel.isAtLeastS());
+        int[] dual_bands = new int[2];
+        dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
+        dual_bands[1] = SoftApConfiguration.BAND_5GHZ;
+        SoftApConfiguration dual_bands_config = new SoftApConfiguration.Builder()
+                .setSsid("ssid")
+                .setBands(dual_bands)
+                .build();
+        assertTrue(Arrays.equals(dual_bands, dual_bands_config.getBands()));
+        assertThat(dual_bands_config.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+    }
+
+    @Test
+    public void testDualChannels() {
+        assumeTrue(SdkLevel.isAtLeastS());
+        int[] expected_dual_bands = new int[2];
+        expected_dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
+        expected_dual_bands[1] = SoftApConfiguration.BAND_5GHZ;
+        SparseIntArray dual_channels = new SparseIntArray(2);
+        dual_channels.put(SoftApConfiguration.BAND_5GHZ, 149);
+        dual_channels.put(SoftApConfiguration.BAND_2GHZ, 2);
+        SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder()
+                .setSsid("ssid")
+                .setChannels(dual_channels)
+                .build();
+        assertTrue(Arrays.equals(expected_dual_bands, dual_channels_config.getBands()));
+        assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+        assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString()));
+        assertThat(dual_channels_config.getChannel()).isEqualTo(2);
+
+        // Test different parameters.
+        dual_channels.clear();
+        dual_channels.put(SoftApConfiguration.BAND_5GHZ, 149);
+        dual_channels.put(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ, 0);
+        expected_dual_bands[0] = SoftApConfiguration.BAND_5GHZ;
+        expected_dual_bands[1] = SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ;
+        dual_channels_config = new SoftApConfiguration.Builder()
+                .setSsid("ssid")
+                .setChannels(dual_channels)
+                .build();
+        assertTrue(Arrays.equals(expected_dual_bands, dual_channels_config.getBands()));
+        assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
+        assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString()));
+        assertThat(dual_channels_config.getChannel()).isEqualTo(149);
+    }
+
+    @Test
+    public void testInvalidBandWhenSetBands() {
+        assumeTrue(SdkLevel.isAtLeastS());
+        boolean isIllegalArgumentExceptionHappened = false;
+        int[] dual_bands = new int[2];
+        dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
+        dual_bands[1] = -1;
+        try {
+            SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder()
+                    .setSsid("ssid")
+                    .setBands(dual_bands)
+                    .build();
+            isIllegalArgumentExceptionHappened = false;
+        } catch (IllegalArgumentException iae) {
+            isIllegalArgumentExceptionHappened = true;
+        }
+        assertTrue(isIllegalArgumentExceptionHappened);
+
+        try {
+            SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder()
+                    .setSsid("ssid")
+                    .setBands(new int[0])
+                    .build();
+            isIllegalArgumentExceptionHappened = false;
+        } catch (IllegalArgumentException iae) {
+            isIllegalArgumentExceptionHappened = true;
+        }
+        assertTrue(isIllegalArgumentExceptionHappened);
+
+        try {
+            SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder()
+                    .setSsid("ssid")
+                    .setBands(new int[3])
+                    .build();
+            isIllegalArgumentExceptionHappened = false;
+        } catch (IllegalArgumentException iae) {
+            isIllegalArgumentExceptionHappened = true;
+        }
+        assertTrue(isIllegalArgumentExceptionHappened);
+    }
+
+    @Test
+    public void testInvalidConfigWhenSetChannels() {
+        assumeTrue(SdkLevel.isAtLeastS());
+        boolean isIllegalArgumentExceptionHappened = false;
+        SparseIntArray invalid_channels = new SparseIntArray();
+        try {
+            SoftApConfiguration zero_channels_config = new SoftApConfiguration.Builder()
+                    .setSsid("ssid")
+                    .setChannels(invalid_channels)
+                    .build();
+            isIllegalArgumentExceptionHappened = false;
+        } catch (IllegalArgumentException iae) {
+            isIllegalArgumentExceptionHappened = true;
+        }
+        assertTrue(isIllegalArgumentExceptionHappened);
+
+        try {
+            invalid_channels.clear();
+            invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2);
+            invalid_channels.put(SoftApConfiguration.BAND_5GHZ, 11);
+            SoftApConfiguration invalid_band_channels_config = new SoftApConfiguration.Builder()
+                    .setSsid("ssid")
+                    .setChannels(invalid_channels)
+                    .build();
+            isIllegalArgumentExceptionHappened = false;
+        } catch (IllegalArgumentException iae) {
+            isIllegalArgumentExceptionHappened = true;
+        }
+        assertTrue(isIllegalArgumentExceptionHappened);
+
+        try {
+            invalid_channels.clear();
+            invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2);
+            invalid_channels.put(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ,
+                    149);
+            SoftApConfiguration invalid_dual_channels_config = new SoftApConfiguration.Builder()
+                    .setSsid("ssid")
+                    .setChannels(invalid_channels)
+                    .build();
+            isIllegalArgumentExceptionHappened = false;
+        } catch (IllegalArgumentException iae) {
+            isIllegalArgumentExceptionHappened = true;
+        }
+        assertTrue(isIllegalArgumentExceptionHappened);
+
+        try {
+            invalid_channels.clear();
+            invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2);
+            invalid_channels.put(SoftApConfiguration.BAND_5GHZ, 149);
+            invalid_channels.put(SoftApConfiguration.BAND_6GHZ, 2);
+            SoftApConfiguration three_channels_config = new SoftApConfiguration.Builder()
+                    .setSsid("ssid")
+                    .setChannels(invalid_channels)
+                    .build();
+            isIllegalArgumentExceptionHappened = false;
+        } catch (IllegalArgumentException iae) {
+            isIllegalArgumentExceptionHappened = true;
+        }
+        assertTrue(isIllegalArgumentExceptionHappened);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalidConfigWhenSet60GhzChannels() throws Exception {
+        SparseIntArray invalid_channels = new SparseIntArray();
+        invalid_channels.put(SoftApConfiguration.BAND_60GHZ, 99);
+        SoftApConfiguration config = new SoftApConfiguration.Builder()
+                .setSsid("ssid")
+                .setChannels(invalid_channels)
+                .build();
+    }
 }
diff --git a/framework/tests/src/android/net/wifi/SoftApInfoTest.java b/framework/tests/src/android/net/wifi/SoftApInfoTest.java
index 929f3ab..2121d10 100644
--- a/framework/tests/src/android/net/wifi/SoftApInfoTest.java
+++ b/framework/tests/src/android/net/wifi/SoftApInfoTest.java
@@ -16,12 +16,15 @@
 
 package android.net.wifi;
 
-import android.os.Parcel;
-
 import static org.junit.Assert.assertEquals;
 
+import android.net.MacAddress;
+import android.os.Parcel;
+
 import androidx.test.filters.SmallTest;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import org.junit.Test;
 
 /**
@@ -29,15 +32,23 @@
  */
 @SmallTest
 public class SoftApInfoTest {
-
+    private static final String TEST_AP_INSTANCE = "wlan1";
+    private static final int TEST_FREQUENCY = 2412;
+    private static final int TEST_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ;
+    private static final int TEST_WIFI_STANDARD = ScanResult.WIFI_STANDARD_LEGACY;
+    private static final MacAddress TEST_AP_MAC = MacAddress.fromString("aa:bb:cc:dd:ee:ff");
     /**
      * Verifies copy constructor.
      */
     @Test
     public void testCopyOperator() throws Exception {
         SoftApInfo info = new SoftApInfo();
-        info.setFrequency(2412);
-        info.setBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ);
+        info.setFrequency(TEST_FREQUENCY);
+        info.setBandwidth(TEST_BANDWIDTH);
+        info.setBssid(TEST_AP_MAC);
+        info.setWifiStandard(TEST_WIFI_STANDARD);
+        info.setApInstanceIdentifier(TEST_AP_INSTANCE);
+
 
         SoftApInfo copiedInfo = new SoftApInfo(info);
 
@@ -51,8 +62,11 @@
     @Test
     public void testParcelOperation() throws Exception {
         SoftApInfo info = new SoftApInfo();
-        info.setFrequency(2412);
-        info.setBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ);
+        info.setFrequency(TEST_FREQUENCY);
+        info.setBandwidth(TEST_BANDWIDTH);
+        info.setBssid(TEST_AP_MAC);
+        info.setWifiStandard(TEST_WIFI_STANDARD);
+        info.setApInstanceIdentifier(TEST_AP_INSTANCE);
 
         Parcel parcelW = Parcel.obtain();
         info.writeToParcel(parcelW, 0);
@@ -68,4 +82,40 @@
         assertEquals(info.hashCode(), fromParcel.hashCode());
     }
 
+
+    /**
+     * Verifies the initial value same as expected.
+     */
+    @Test
+    public void testInitialValue() throws Exception {
+        SoftApInfo info = new SoftApInfo();
+        assertEquals(info.getFrequency(), 0);
+        assertEquals(info.getBandwidth(), SoftApInfo.CHANNEL_WIDTH_INVALID);
+        if (SdkLevel.isAtLeastS()) {
+            assertEquals(info.getBssid(), null);
+            assertEquals(info.getWifiStandard(), ScanResult.WIFI_STANDARD_UNKNOWN);
+            assertEquals(info.getApInstanceIdentifier(), null);
+        }
+    }
+
+    /**
+     * Verifies the set/get method same as expected.
+     */
+    @Test
+    public void testGetXXXAlignedWithSetXXX() throws Exception {
+        SoftApInfo info = new SoftApInfo();
+        info.setFrequency(TEST_FREQUENCY);
+        info.setBandwidth(TEST_BANDWIDTH);
+        info.setBssid(TEST_AP_MAC);
+        info.setWifiStandard(TEST_WIFI_STANDARD);
+        info.setApInstanceIdentifier(TEST_AP_INSTANCE);
+        assertEquals(info.getFrequency(), TEST_FREQUENCY);
+        assertEquals(info.getBandwidth(), TEST_BANDWIDTH);
+        if (SdkLevel.isAtLeastS()) {
+            assertEquals(info.getBssid(), TEST_AP_MAC);
+            assertEquals(info.getWifiStandard(), TEST_WIFI_STANDARD);
+            assertEquals(info.getApInstanceIdentifier(), TEST_AP_INSTANCE);
+        }
+    }
+
 }
diff --git a/framework/tests/src/android/net/wifi/WifiClientTest.java b/framework/tests/src/android/net/wifi/WifiClientTest.java
index 7a3baf9..7046563 100644
--- a/framework/tests/src/android/net/wifi/WifiClientTest.java
+++ b/framework/tests/src/android/net/wifi/WifiClientTest.java
@@ -42,9 +42,9 @@
      */
     @Test
     public void testWifiClientParcelWriteRead() throws Exception {
-        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
+        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS, INTERFACE_NAME);
 
-        assertParcelSane(writeWifiClient, 1);
+        assertParcelSane(writeWifiClient, 2);
     }
 
     /**
@@ -52,12 +52,12 @@
      */
     @Test
     public void testWifiClientEquals() throws Exception {
-        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
-        WifiClient writeWifiClientEquals = new WifiClient(MAC_ADDRESS);
+        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS, INTERFACE_NAME);
+        WifiClient writeWifiClientEquals = new WifiClient(MAC_ADDRESS, INTERFACE_NAME);
 
         assertEquals(writeWifiClient, writeWifiClientEquals);
         assertEquals(writeWifiClient.hashCode(), writeWifiClientEquals.hashCode());
-        assertFieldCountEquals(1, WifiClient.class);
+        assertFieldCountEquals(2, WifiClient.class);
     }
 
     /**
@@ -66,8 +66,8 @@
     @Test
     public void testWifiClientNotEquals() throws Exception {
         final MacAddress macAddressNotEquals = MacAddress.fromString("00:00:00:00:00:00");
-        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
-        WifiClient writeWifiClientNotEquals = new WifiClient(macAddressNotEquals);
+        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS, INTERFACE_NAME);
+        WifiClient writeWifiClientNotEquals = new WifiClient(macAddressNotEquals, INTERFACE_NAME);
 
         assertNotEquals(writeWifiClient, writeWifiClientNotEquals);
         assertNotEquals(writeWifiClient.hashCode(), writeWifiClientNotEquals.hashCode());
diff --git a/framework/tests/src/android/net/wifi/WifiConfigurationTest.java b/framework/tests/src/android/net/wifi/WifiConfigurationTest.java
index 890d3d3..bde44e7 100644
--- a/framework/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/framework/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -17,12 +17,18 @@
 package android.net.wifi;
 
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP;
-import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OSEN;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WEP;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -32,9 +38,13 @@
 import static org.junit.Assert.assertTrue;
 
 import android.net.MacAddress;
+import android.net.wifi.WifiConfiguration.GroupCipher;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
+import android.net.wifi.WifiConfiguration.PairwiseCipher;
+import android.net.wifi.WifiConfiguration.Protocol;
 import android.os.Parcel;
+import android.util.Pair;
 
 import androidx.test.filters.SmallTest;
 
@@ -43,11 +53,19 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
 /**
  * Unit tests for {@link android.net.wifi.WifiConfiguration}.
  */
 @SmallTest
 public class WifiConfigurationTest {
+    private static final String TEST_PASSPOINT_UNIQUE_ID = "uniqueId";
+    private static final int TEST_CARRIER_ID = 1234;
+    private static final int TEST_SUB_ID = 3;
+    private static final String TEST_PACKAGE_NAME = "google.com";
 
     @Before
     public void setUp() {
@@ -67,11 +85,16 @@
         WifiConfiguration config = new WifiConfiguration();
         config.setPasspointManagementObjectTree(cookie);
         config.trusted = false;
+        config.oemPaid = true;
+        config.oemPrivate = true;
+        config.carrierMerged = true;
         config.updateIdentifier = "1234";
         config.fromWifiNetworkSpecifier = true;
         config.fromWifiNetworkSuggestion = true;
         config.setRandomizedMacAddress(MacAddressUtils.createRandomUnicastAddress());
         MacAddress macBeforeParcel = config.getRandomizedMacAddress();
+        config.subscriptionId = 1;
+        config.carrierId = 1189;
         Parcel parcelW = Parcel.obtain();
         config.writeToParcel(parcelW, 0);
         byte[] bytes = parcelW.marshall();
@@ -87,8 +110,11 @@
         assertEquals(macBeforeParcel, reconfig.getRandomizedMacAddress());
         assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
         assertFalse(reconfig.trusted);
-        assertTrue(config.fromWifiNetworkSpecifier);
-        assertTrue(config.fromWifiNetworkSuggestion);
+        assertTrue(reconfig.fromWifiNetworkSpecifier);
+        assertTrue(reconfig.fromWifiNetworkSuggestion);
+        assertTrue(reconfig.oemPaid);
+        assertTrue(reconfig.oemPrivate);
+        assertTrue(reconfig.carrierMerged);
 
         Parcel parcelWW = Parcel.obtain();
         reconfig.writeToParcel(parcelWW, 0);
@@ -99,6 +125,34 @@
     }
 
     @Test
+    public void testWifiConfigurationCopyConstructor() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.trusted = false;
+        config.oemPaid = true;
+        config.oemPrivate = true;
+        config.carrierMerged = true;
+        config.updateIdentifier = "1234";
+        config.fromWifiNetworkSpecifier = true;
+        config.fromWifiNetworkSuggestion = true;
+        config.setRandomizedMacAddress(MacAddressUtils.createRandomUnicastAddress());
+        MacAddress macBeforeParcel = config.getRandomizedMacAddress();
+        config.subscriptionId = 1;
+        config.carrierId = 1189;
+
+        WifiConfiguration reconfig = new WifiConfiguration(config);
+
+        // lacking a useful config.equals, check two fields near the end.
+        assertEquals(macBeforeParcel, reconfig.getRandomizedMacAddress());
+        assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
+        assertFalse(reconfig.trusted);
+        assertTrue(reconfig.fromWifiNetworkSpecifier);
+        assertTrue(reconfig.fromWifiNetworkSuggestion);
+        assertTrue(reconfig.oemPaid);
+        assertTrue(reconfig.oemPrivate);
+        assertTrue(reconfig.carrierMerged);
+    }
+
+    @Test
     public void testIsOpenNetwork_IsOpen_NullWepKeys() {
         WifiConfiguration config = new WifiConfiguration();
         config.allowedKeyManagement.clear();
@@ -145,18 +199,24 @@
 
     @Test
     public void testIsOpenNetwork_NotOpen_HasAuthType() {
-        for (int keyMgmt = 0; keyMgmt < WifiConfiguration.KeyMgmt.strings.length; keyMgmt++) {
-            if (keyMgmt == WifiConfiguration.KeyMgmt.NONE
-                    || keyMgmt == WifiConfiguration.KeyMgmt.OWE) {
-                continue;
-            }
+        int[] securityTypes = new int [] {
+                SECURITY_TYPE_WEP,
+                SECURITY_TYPE_PSK,
+                SECURITY_TYPE_EAP,
+                SECURITY_TYPE_SAE,
+                SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
+                SECURITY_TYPE_WAPI_PSK,
+                SECURITY_TYPE_WAPI_CERT,
+                SECURITY_TYPE_EAP_WPA3_ENTERPRISE,
+                SECURITY_TYPE_OSEN,
+        };
+        for (int type: securityTypes) {
             WifiConfiguration config = new WifiConfiguration();
-            config.allowedKeyManagement.clear();
-            config.allowedKeyManagement.set(keyMgmt);
+            config.setSecurityParams(type);
             config.wepKeys = null;
 
-            assertFalse("Open network reported when key mgmt was set to "
-                            + WifiConfiguration.KeyMgmt.strings[keyMgmt], config.isOpenNetwork());
+            assertFalse("Open network reported when security type was set to "
+                            + type, config.isOpenNetwork());
         }
     }
 
@@ -166,6 +226,7 @@
         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
         config.wepKeys = null;
+        config.convertLegacyFieldsToSecurityParamsIfNeeded();
 
         assertFalse(config.isOpenNetwork());
     }
@@ -388,6 +449,79 @@
     }
 
     /**
+     * Verifies that getNetworkKey returns the correct String for networks of
+     * various different security types, the result should be stable.
+     */
+    @Test
+    public void testGetNetworkKeyString() {
+        WifiConfiguration config = new WifiConfiguration();
+        final String mSsid = "TestAP";
+        config.SSID = mSsid;
+
+        // Test various combinations
+        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK],
+                config.getNetworkKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP],
+                config.getNetworkKey());
+
+        config.wepKeys[0] = "TestWep";
+        config.allowedKeyManagement.clear();
+        assertEquals(mSsid + "WEP", config.getNetworkKey());
+
+        // set WEP key and give a valid index.
+        config.wepKeys[0] = null;
+        config.wepKeys[2] = "TestWep";
+        config.wepTxKeyIndex = 2;
+        config.allowedKeyManagement.clear();
+        assertEquals(mSsid + "WEP", config.getNetworkKey());
+
+        // set WEP key but does not give a valid index.
+        config.wepKeys[0] = null;
+        config.wepKeys[2] = "TestWep";
+        config.wepTxKeyIndex = 0;
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.OWE);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getNetworkKey());
+
+        config.wepKeys[0] = null;
+        config.wepTxKeyIndex = 0;
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.OWE);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getNetworkKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.SAE);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SAE], config.getNetworkKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SUITE_B_192],
+                config.getNetworkKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getNetworkKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.WAPI_PSK);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_PSK],
+                config.getNetworkKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.WAPI_CERT);
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_CERT],
+                config.getNetworkKey());
+
+        config.allowedKeyManagement.clear();
+        config.setPasspointUniqueId(TEST_PASSPOINT_UNIQUE_ID);
+        assertEquals(TEST_PASSPOINT_UNIQUE_ID, config.getNetworkKey());
+    }
+
+    /**
      * Ensure that the {@link NetworkSelectionStatus.DisableReasonInfo}s are populated in
      * {@link NetworkSelectionStatus#DISABLE_REASON_INFOS} for reason codes from 0 to
      * {@link NetworkSelectionStatus#NETWORK_SELECTION_DISABLED_MAX} - 1.
@@ -462,7 +596,7 @@
     public void testSetSecurityParamsForSuiteB() throws Exception {
         WifiConfiguration config = new WifiConfiguration();
 
-        config.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+        config.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
 
         assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
         assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
@@ -475,6 +609,26 @@
     }
 
     /**
+     * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+     * {@link WifiConfiguration} object correctly for WPA3 Enterprise security type.
+     * @throws Exception
+     */
+    @Test
+    public void testSetSecurityParamsForWpa3Enterprise() throws Exception {
+        WifiConfiguration config = new WifiConfiguration();
+
+        config.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+
+        assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
+        assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+        assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+        assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+        assertTrue(config.requirePmf);
+    }
+
+    /**
      * Test that the NetworkSelectionStatus Builder returns the same values that was set, and that
      * calling build multiple times returns different instances.
      */
@@ -535,7 +689,512 @@
         configuration.setSecurityParams(SECURITY_TYPE_EAP);
         assertFalse(configuration.needsPreSharedKey());
 
-        configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+        configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
         assertFalse(configuration.needsPreSharedKey());
+
+        configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
+        assertFalse(configuration.needsPreSharedKey());
+    }
+
+    @Test
+    public void testGetAuthType() throws Exception {
+        WifiConfiguration configuration = new WifiConfiguration();
+
+        configuration.setSecurityParams(SECURITY_TYPE_PSK);
+        assertEquals(KeyMgmt.WPA_PSK, configuration.getAuthType());
+
+        configuration.setSecurityParams(SECURITY_TYPE_SAE);
+        assertEquals(KeyMgmt.SAE, configuration.getAuthType());
+
+        configuration.setSecurityParams(SECURITY_TYPE_WAPI_PSK);
+        assertEquals(KeyMgmt.WAPI_PSK, configuration.getAuthType());
+
+        configuration.setSecurityParams(SECURITY_TYPE_OPEN);
+        assertEquals(KeyMgmt.NONE, configuration.getAuthType());
+
+        configuration.setSecurityParams(SECURITY_TYPE_OWE);
+        assertEquals(KeyMgmt.OWE, configuration.getAuthType());
+
+        configuration.setSecurityParams(SECURITY_TYPE_EAP);
+        assertEquals(KeyMgmt.WPA_EAP, configuration.getAuthType());
+
+        configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+        assertEquals(KeyMgmt.WPA_EAP, configuration.getAuthType());
+
+        configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
+        assertEquals(KeyMgmt.SUITE_B_192, configuration.getAuthType());
+
+        configuration.setSecurityParams(SECURITY_TYPE_WAPI_CERT);
+        assertEquals(KeyMgmt.WAPI_CERT, configuration.getAuthType());
+    }
+
+    @Test (expected = IllegalStateException.class)
+    public void testGetAuthTypeFailure1() throws Exception {
+        WifiConfiguration configuration = new WifiConfiguration();
+
+        configuration.setSecurityParams(SECURITY_TYPE_PSK);
+        configuration.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+        configuration.getAuthType();
+    }
+
+    @Test (expected = IllegalStateException.class)
+    public void testGetAuthTypeFailure2() throws Exception {
+        WifiConfiguration configuration = new WifiConfiguration();
+
+        configuration.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+        configuration.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        configuration.allowedKeyManagement.set(KeyMgmt.SAE);
+        configuration.getAuthType();
+    }
+
+    /**
+     * Verifies that getProfileKey returns the correct String for networks of
+     * various different security types, the result should be stable.
+     */
+    @Test
+    public void testGetProfileKeyString() {
+        WifiConfiguration config = new WifiConfiguration();
+        final String mSsid = "TestAP";
+        config.SSID = mSsid;
+        config.carrierId = TEST_CARRIER_ID;
+        config.subscriptionId = TEST_SUB_ID;
+        config.creatorName = TEST_PACKAGE_NAME;
+
+
+        // Test various combinations
+        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WPA_PSK], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WPA_PSK], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WPA_EAP], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WPA_EAP], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.wepKeys[0] = "TestWep";
+        config.allowedKeyManagement.clear();
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, "WEP", TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, "WEP", TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        // set WEP key and give a valid index.
+        config.wepKeys[0] = null;
+        config.wepKeys[2] = "TestWep";
+        config.wepTxKeyIndex = 2;
+        config.allowedKeyManagement.clear();
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, "WEP", TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, "WEP", TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        // set WEP key but does not give a valid index.
+        config.wepKeys[0] = null;
+        config.wepKeys[2] = "TestWep";
+        config.wepTxKeyIndex = 0;
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.OWE);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.OWE], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.OWE], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.wepKeys[0] = null;
+        config.wepTxKeyIndex = 0;
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.OWE);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.OWE], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.OWE], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.SAE);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.SAE], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.SAE], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.SUITE_B_192],
+                TEST_PACKAGE_NAME, TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.SUITE_B_192],
+                TEST_PACKAGE_NAME, TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.NONE);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.NONE], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.NONE], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.WAPI_PSK);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WAPI_PSK], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WAPI_PSK], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.WAPI_CERT);
+        config.fromWifiNetworkSuggestion = false;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WAPI_CERT], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+        config.fromWifiNetworkSuggestion = true;
+        assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WAPI_CERT], TEST_PACKAGE_NAME,
+                TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+        config.allowedKeyManagement.clear();
+        config.setPasspointUniqueId(TEST_PASSPOINT_UNIQUE_ID);
+        assertEquals(TEST_PASSPOINT_UNIQUE_ID, config.getProfileKey());
+    }
+
+    private String createProfileKey(String ssid, String keyMgmt, String providerName,
+            int carrierId, int subId, boolean isFromSuggestion) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(ssid).append(keyMgmt);
+        if (isFromSuggestion) {
+            sb.append("_").append(providerName).append('-')
+                    .append(carrierId).append('-').append(subId);
+        }
+        return sb.toString();
+    }
+
+    private void verifyAllowedKeyManagement(WifiConfiguration config, int[] akms) {
+        for (int akm: akms) {
+            assertTrue(config.getSecurityParamsList().stream()
+                    .anyMatch(params -> params.getAllowedKeyManagement().get(akm)));
+        }
+    }
+
+    private void verifyAllowedProtocols(WifiConfiguration config, int[] aps) {
+        for (int ap: aps) {
+            assertTrue(config.getSecurityParamsList().stream()
+                    .anyMatch(params -> params.getAllowedProtocols().get(ap)));
+        }
+    }
+
+    private void verifyAllowedPairwiseCiphers(WifiConfiguration config, int[] apcs) {
+        for (int apc: apcs) {
+            assertTrue(config.getSecurityParamsList().stream()
+                    .anyMatch(params -> params.getAllowedPairwiseCiphers().get(apc)));
+        }
+    }
+
+    private void verifyAllowedGroupCiphers(WifiConfiguration config, int[] agcs) {
+        for (int agc: agcs) {
+            assertTrue(config.getSecurityParamsList().stream()
+                    .anyMatch(params -> params.getAllowedGroupCiphers().get(agc)));
+        }
+    }
+
+    /** Verify that adding security types works as expected. */
+    @Test
+    public void testAddSecurityTypes() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_PSK);
+        List<SecurityParams> paramsList = config.getSecurityParamsList();
+        assertEquals(3, paramsList.size());
+
+        verifyAllowedKeyManagement(config, new int[] {
+                KeyMgmt.WPA_PSK, KeyMgmt.SAE, KeyMgmt.WAPI_PSK});
+        verifyAllowedProtocols(config, new int[] {Protocol.WPA, Protocol.RSN, Protocol.WAPI});
+        verifyAllowedPairwiseCiphers(config, new int[] {
+                PairwiseCipher.CCMP, PairwiseCipher.TKIP,
+                PairwiseCipher.GCMP_128, PairwiseCipher.GCMP_256,
+                PairwiseCipher.SMS4});
+        verifyAllowedGroupCiphers(config, new int[] {
+                GroupCipher.CCMP, GroupCipher.TKIP,
+                GroupCipher.GCMP_128, GroupCipher.GCMP_256,
+                GroupCipher.SMS4});
+    }
+
+    /** Check that a personal security type can be added to a personal configuration. */
+    @Test
+    public void testAddPersonalTypeToPersonalConfiguration() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+    }
+
+    /** Check that an enterprise security type can be added to an enterprise configuration. */
+    @Test
+    public void testAddEnterpriseTypeToEnterpriseConfiguration() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+    }
+
+    /** Verify that adding an enterprise type to a personal configuration. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testAddEnterpriseTypeToPersonalConfig() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
+    }
+
+    /** Verify that adding a personal type to an enterprise configuration. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testAddPersonalTypeToEnterpriseConfig() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+    }
+
+    /** Check that an open security cannot be added to a non-open configuration. */
+    @Test(expected = IllegalArgumentException.class)
+    public void testAddOpenTypeToNonOpenConfiguration() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
+    }
+
+    /** Check that a non-open security cannot be added to an open configuration. */
+    @Test(expected = IllegalArgumentException.class)
+    public void testAddNonOpenTypeToOpenConfiguration() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+    }
+
+    /** Check that a OSEN security cannot be added as additional type. */
+    @Test(expected = IllegalArgumentException.class)
+    public void testAddOsenTypeToConfiguration() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_OSEN);
+    }
+
+    /** Verify that adding duplicate security types raises the exception. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testAddDuplicateSecurityTypes() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+    }
+
+    /** Verify that adding duplicate security params raises the exception. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testAddDuplicateSecurityParams() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+    }
+
+    /** Verify that Suite-B type works as expected. */
+    @Test
+    public void testAddSuiteBSecurityType() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
+
+        assertFalse(config.isSuiteBCipherEcdheRsaEnabled());
+        config.enableSuiteBCiphers(false, true);
+        assertTrue(config.isSuiteBCipherEcdheRsaEnabled());
+    }
+
+    /** Verify that FILS bit can be set correctly. */
+    @Test
+    public void testFilsKeyMgmt() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+
+        config.enableFils(false, true);
+        assertFalse(config.isFilsSha256Enabled());
+        assertTrue(config.isFilsSha384Enabled());
+    }
+
+    /** Verify that SAE mode can be configured correctly. */
+    @Test
+    public void testSaeTypeMethods() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+
+        SecurityParams saeParams = config.getSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+        assertNotNull(saeParams);
+        assertFalse(saeParams.isSaeH2eOnlyMode());
+        assertFalse(saeParams.isSaePkOnlyMode());
+
+        config.enableSaeH2eOnlyMode(true);
+        config.enableSaePkOnlyMode(true);
+
+        saeParams = config.getSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+        assertNotNull(saeParams);
+        assertTrue(saeParams.isSaeH2eOnlyMode());
+        assertTrue(saeParams.isSaePkOnlyMode());
+    }
+
+    /** Verify the legacy configuration conversion */
+    @Test
+    public void testLegacyConfigurationConversion() {
+        Pair[] keyMgmtSecurityTypePairs = new Pair[] {
+                new Pair<>(KeyMgmt.WAPI_CERT, SECURITY_TYPE_WAPI_CERT),
+                new Pair<>(KeyMgmt.WAPI_PSK, SECURITY_TYPE_WAPI_PSK),
+                new Pair<>(KeyMgmt.SUITE_B_192, SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+                new Pair<>(KeyMgmt.OWE, SECURITY_TYPE_OWE),
+                new Pair<>(KeyMgmt.SAE, SECURITY_TYPE_SAE),
+                new Pair<>(KeyMgmt.OSEN, SECURITY_TYPE_OSEN),
+                new Pair<>(KeyMgmt.WPA2_PSK, SECURITY_TYPE_PSK),
+                new Pair<>(KeyMgmt.WPA_EAP, SECURITY_TYPE_EAP),
+                new Pair<>(KeyMgmt.WPA_PSK, SECURITY_TYPE_PSK),
+                new Pair<>(KeyMgmt.NONE, SECURITY_TYPE_OPEN),
+        };
+
+        for (Pair pair: keyMgmtSecurityTypePairs) {
+            WifiConfiguration config = new WifiConfiguration();
+            config.allowedKeyManagement.set((int) pair.first);
+            config.convertLegacyFieldsToSecurityParamsIfNeeded();
+            assertNotNull(config.getSecurityParams((int) pair.second));
+        }
+
+        // If none of key management is set, it should be open.
+        WifiConfiguration emptyConfig = new WifiConfiguration();
+        emptyConfig.convertLegacyFieldsToSecurityParamsIfNeeded();
+        assertNotNull(emptyConfig.getSecurityParams(SECURITY_TYPE_OPEN));
+
+        // If EAP key management is set and requirePmf is true, it is WPA3 Enterprise.
+        WifiConfiguration wpa3EnterpriseConfig = new WifiConfiguration();
+        wpa3EnterpriseConfig.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        wpa3EnterpriseConfig.requirePmf = true;
+        wpa3EnterpriseConfig.convertLegacyFieldsToSecurityParamsIfNeeded();
+        assertNotNull(wpa3EnterpriseConfig.getSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
+
+        // If key management is NONE and wep key is set, it is WEP type.
+        WifiConfiguration wepConfig = new WifiConfiguration();
+        wepConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+        wepConfig.wepKeys = new String[] {"\"abcdef\""};
+        wepConfig.convertLegacyFieldsToSecurityParamsIfNeeded();
+        assertNotNull(wepConfig.getSecurityParams(SECURITY_TYPE_WEP));
+    }
+
+    /** Verify the set security params by SecurityParams objects. */
+    @Test
+    public void testSetBySecurityParamsObject() {
+        int[] securityTypes = new int[] {
+                SECURITY_TYPE_WAPI_CERT,
+                SECURITY_TYPE_WAPI_PSK,
+                SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
+                SECURITY_TYPE_OWE,
+                SECURITY_TYPE_SAE,
+                SECURITY_TYPE_OSEN,
+                SECURITY_TYPE_EAP,
+                SECURITY_TYPE_PSK,
+                SECURITY_TYPE_OPEN,
+                SECURITY_TYPE_PASSPOINT_R1_R2,
+                SECURITY_TYPE_PASSPOINT_R3,
+        };
+        for (int type: securityTypes) {
+            WifiConfiguration config = new WifiConfiguration();
+            config.setSecurityParams(type);
+            assertTrue(config.isSecurityType(type));
+            assertNotNull(config.getSecurityParams(type));
+        }
+    }
+
+    /** Verify the set security params by an allowed key management mask. */
+    @Test
+    public void testSetSecurityParamsByAllowedKeyManagement() {
+        Pair[] keyMgmtSecurityTypePairs = new Pair[] {
+                new Pair<>(KeyMgmt.WAPI_CERT, SECURITY_TYPE_WAPI_CERT),
+                new Pair<>(KeyMgmt.WAPI_PSK, SECURITY_TYPE_WAPI_PSK),
+                new Pair<>(KeyMgmt.SUITE_B_192, SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+                new Pair<>(KeyMgmt.OWE, SECURITY_TYPE_OWE),
+                new Pair<>(KeyMgmt.SAE, SECURITY_TYPE_SAE),
+                new Pair<>(KeyMgmt.OSEN, SECURITY_TYPE_OSEN),
+                new Pair<>(KeyMgmt.WPA2_PSK, SECURITY_TYPE_PSK),
+                new Pair<>(KeyMgmt.WPA_EAP, SECURITY_TYPE_EAP),
+                new Pair<>(KeyMgmt.WPA_PSK, SECURITY_TYPE_PSK),
+                new Pair<>(KeyMgmt.NONE, SECURITY_TYPE_OPEN),
+        };
+
+        for (Pair pair: keyMgmtSecurityTypePairs) {
+            BitSet akm = new BitSet();
+            akm.set((int) pair.first);
+            WifiConfiguration config = new WifiConfiguration();
+            config.setSecurityParams(akm);
+            assertNotNull(config.getSecurityParams((int) pair.second));
+        }
+    }
+
+    /** Verify the set security params by an invalid allowed key management mask. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testSetSecurityParamsByInvalidAllowedKeyManagement() {
+        WifiConfiguration config = new WifiConfiguration();
+        BitSet akm = null;
+        config.setSecurityParams(akm);
+    }
+
+    /** Verify the set security params by a security params list. */
+    @Test
+    public void testSetSecurityParamsBySecurityParamsList() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+        config.addSecurityParams(SECURITY_TYPE_EAP);
+        config.addSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+        assertTrue(config.isSecurityType(SECURITY_TYPE_EAP));
+        assertTrue(config.isSecurityType(SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
+        assertFalse(config.isSecurityType(SECURITY_TYPE_PSK));
+        assertFalse(config.isSecurityType(SECURITY_TYPE_SAE));
+
+        List<SecurityParams> list = new ArrayList<>();
+        list.add(SecurityParams.createSecurityParamsBySecurityType(SECURITY_TYPE_PSK));
+        list.add(SecurityParams.createSecurityParamsBySecurityType(SECURITY_TYPE_SAE));
+        config.setSecurityParams(list);
+        assertFalse(config.isSecurityType(SECURITY_TYPE_EAP));
+        assertFalse(config.isSecurityType(SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
+        assertTrue(config.isSecurityType(SECURITY_TYPE_PSK));
+        assertTrue(config.isSecurityType(SECURITY_TYPE_SAE));
+    }
+
+    /** Verify the set security params by an empty security params list. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testSetSecurityParamsByEmptySecurityParamsList() {
+        WifiConfiguration config = new WifiConfiguration();
+        List<SecurityParams> list = new ArrayList<>();
+        config.setSecurityParams(list);
+    }
+
+    /** Verify the set security params by a null security params list. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testSetSecurityParamsByNullSecurityParamsList() {
+        WifiConfiguration config = new WifiConfiguration();
+        List<SecurityParams> list = null;
+        config.setSecurityParams(list);
     }
 }
diff --git a/framework/tests/src/android/net/wifi/WifiInfoTest.java b/framework/tests/src/android/net/wifi/WifiInfoTest.java
index 311bbc4..33438ed 100644
--- a/framework/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/framework/tests/src/android/net/wifi/WifiInfoTest.java
@@ -17,11 +17,13 @@
 package android.net.wifi;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
+import android.telephony.SubscriptionManager;
 
 import androidx.test.filters.SmallTest;
 
@@ -49,6 +51,7 @@
     private static final int TEST_RSSI = -60;
     private static final int TEST_NETWORK_ID = 5;
     private static final int TEST_NETWORK_ID2 = 6;
+    private static final int TEST_SUB_ID = 1;
 
     /**
      *  Verify parcel write/read with WifiInfo.
@@ -61,6 +64,9 @@
         writeWifiInfo.txBad = TEST_TX_BAD;
         writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
         writeWifiInfo.setTrusted(true);
+        writeWifiInfo.setOemPaid(true);
+        writeWifiInfo.setOemPrivate(true);
+        writeWifiInfo.setCarrierMerged(true);
         writeWifiInfo.setOsuAp(true);
         writeWifiInfo.setFQDN(TEST_FQDN);
         writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
@@ -68,6 +74,7 @@
         writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD);
         writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
         writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
+        writeWifiInfo.setSubscriptionId(TEST_SUB_ID);
 
         Parcel parcel = Parcel.obtain();
         writeWifiInfo.writeToParcel(parcel, 0);
@@ -81,6 +88,9 @@
         assertEquals(TEST_TX_BAD, readWifiInfo.txBad);
         assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
         assertTrue(readWifiInfo.isTrusted());
+        assertTrue(readWifiInfo.isOemPaid());
+        assertTrue(readWifiInfo.isOemPrivate());
+        assertTrue(readWifiInfo.isCarrierMerged());
         assertTrue(readWifiInfo.isOsuAp());
         assertTrue(readWifiInfo.isPasspointAp());
         assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName());
@@ -91,6 +101,50 @@
                 readWifiInfo.getMaxSupportedTxLinkSpeedMbps());
         assertEquals(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS,
                 readWifiInfo.getMaxSupportedRxLinkSpeedMbps());
+        assertEquals(TEST_SUB_ID, readWifiInfo.getSubscriptionId());
+    }
+
+    @Test
+    public void testWifiInfoCopyConstructor() throws Exception {
+        WifiInfo writeWifiInfo = new WifiInfo();
+        writeWifiInfo.txSuccess = TEST_TX_SUCCESS;
+        writeWifiInfo.txRetries = TEST_TX_RETRIES;
+        writeWifiInfo.txBad = TEST_TX_BAD;
+        writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
+        writeWifiInfo.setTrusted(true);
+        writeWifiInfo.setOemPaid(true);
+        writeWifiInfo.setOemPrivate(true);
+        writeWifiInfo.setCarrierMerged(true);
+        writeWifiInfo.setOsuAp(true);
+        writeWifiInfo.setFQDN(TEST_FQDN);
+        writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
+        writeWifiInfo.setRequestingPackageName(TEST_PACKAGE_NAME);
+        writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD);
+        writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
+        writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
+        writeWifiInfo.setSubscriptionId(TEST_SUB_ID);
+
+        WifiInfo readWifiInfo = new WifiInfo(writeWifiInfo);
+
+        assertEquals(TEST_TX_SUCCESS, readWifiInfo.txSuccess);
+        assertEquals(TEST_TX_RETRIES, readWifiInfo.txRetries);
+        assertEquals(TEST_TX_BAD, readWifiInfo.txBad);
+        assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
+        assertTrue(readWifiInfo.isTrusted());
+        assertTrue(readWifiInfo.isOemPaid());
+        assertTrue(readWifiInfo.isOemPrivate());
+        assertTrue(readWifiInfo.isCarrierMerged());
+        assertTrue(readWifiInfo.isOsuAp());
+        assertTrue(readWifiInfo.isPasspointAp());
+        assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName());
+        assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn());
+        assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName());
+        assertEquals(TEST_WIFI_STANDARD, readWifiInfo.getWifiStandard());
+        assertEquals(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS,
+                readWifiInfo.getMaxSupportedTxLinkSpeedMbps());
+        assertEquals(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS,
+                readWifiInfo.getMaxSupportedRxLinkSpeedMbps());
+        assertEquals(TEST_SUB_ID, readWifiInfo.getSubscriptionId());
     }
 
     /**
@@ -108,6 +162,10 @@
         assertEquals(WifiManager.UNKNOWN_SSID, wifiInfo.getSSID());
         assertEquals(null, wifiInfo.getBSSID());
         assertEquals(-1, wifiInfo.getNetworkId());
+        assertFalse(wifiInfo.isOemPaid());
+        assertFalse(wifiInfo.isOemPrivate());
+        assertFalse(wifiInfo.isCarrierMerged());
+        assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, wifiInfo.getSubscriptionId());
     }
 
     /**
diff --git a/framework/tests/src/android/net/wifi/WifiManagerTest.java b/framework/tests/src/android/net/wifi/WifiManagerTest.java
index 1398bfe..274cff2 100644
--- a/framework/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/framework/tests/src/android/net/wifi/WifiManagerTest.java
@@ -19,6 +19,9 @@
 import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED;
 import static android.net.wifi.WifiManager.ActionListener;
 import static android.net.wifi.WifiManager.BUSY;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_SOFTAP;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_AWARE;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_DIRECT;
 import static android.net.wifi.WifiManager.ERROR;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
@@ -33,6 +36,8 @@
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_ADDITIONAL_STA;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_AP_STA;
 import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP;
 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
 import static android.net.wifi.WifiManager.WIFI_FEATURE_P2P;
@@ -41,6 +46,7 @@
 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
 import static android.net.wifi.WifiManager.WpsCallback;
+import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -49,6 +55,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
@@ -60,6 +67,7 @@
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -71,6 +79,7 @@
 import android.content.pm.ApplicationInfo;
 import android.net.DhcpInfo;
 import android.net.MacAddress;
+import android.net.wifi.WifiManager.CoexCallback;
 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
 import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
 import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
@@ -81,9 +90,9 @@
 import android.net.wifi.WifiManager.ScanResultsCallback;
 import android.net.wifi.WifiManager.SoftApCallback;
 import android.net.wifi.WifiManager.SuggestionConnectionStatusListener;
+import android.net.wifi.WifiManager.SuggestionUserApprovalStatusListener;
 import android.net.wifi.WifiManager.TrafficStateCallback;
 import android.net.wifi.WifiManager.WifiConnectedNetworkScorer;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerExecutor;
@@ -95,18 +104,23 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /**
@@ -123,8 +137,18 @@
     private static final String TEST_FEATURE_ID = "TestFeature";
     private static final String TEST_COUNTRY_CODE = "US";
     private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"};
-    private static final int TEST_AP_FREQUENCY = 2412;
-    private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ;
+    private static final int TEST_SUB_ID = 3;
+    private static final String[] TEST_AP_INSTANCES = new String[] {"wlan1", "wlan2"};
+    private static final int[] TEST_AP_FREQS = new int[] {2412, 5220};
+    private static final int[] TEST_AP_BWS = new int[] {SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT,
+            SoftApInfo.CHANNEL_WIDTH_80MHZ};
+    private static final MacAddress[] TEST_AP_BSSIDS = new MacAddress[] {
+            MacAddress.fromString("22:33:44:55:66:77"),
+            MacAddress.fromString("aa:bb:cc:dd:ee:ff")};
+    private static final MacAddress[] TEST_AP_CLIENTS = new MacAddress[] {
+            MacAddress.fromString("22:33:44:aa:aa:77"),
+            MacAddress.fromString("aa:bb:cc:11:11:ff"),
+            MacAddress.fromString("22:bb:cc:11:aa:ff")};
 
     @Mock Context mContext;
     @Mock android.net.wifi.IWifiManager mWifiService;
@@ -135,20 +159,27 @@
     @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
     @Mock OnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener;
     @Mock OnWifiActivityEnergyInfoListener mOnWifiActivityEnergyInfoListener;
-    @Mock SuggestionConnectionStatusListener mListener;
+    @Mock SuggestionConnectionStatusListener mSuggestionConnectionListener;
     @Mock Runnable mRunnable;
     @Mock Executor mExecutor;
     @Mock Executor mAnotherExecutor;
     @Mock ActivityManager mActivityManager;
     @Mock WifiConnectedNetworkScorer mWifiConnectedNetworkScorer;
+    @Mock SuggestionUserApprovalStatusListener mSuggestionUserApprovalStatusListener;
 
     private Handler mHandler;
     private TestLooper mLooper;
     private WifiManager mWifiManager;
     private WifiNetworkSuggestion mWifiNetworkSuggestion;
     private ScanResultsCallback mScanResultsCallback;
+    private CoexCallback mCoexCallback;
     private WifiActivityEnergyInfo mWifiActivityEnergyInfo;
 
+    private HashMap<String, SoftApInfo> mTestSoftApInfoMap = new HashMap<>();
+    private HashMap<String, List<WifiClient>> mTestWifiClientsMap = new HashMap<>();
+    private SoftApInfo mTestApInfo1 = new SoftApInfo();
+    private SoftApInfo mTestApInfo2 = new SoftApInfo();
+
     /**
      * Util function to check public field which used for softap  in WifiConfiguration
      * same as the value in SoftApConfiguration.
@@ -193,6 +224,31 @@
                 .build();
     }
 
+    private void initTestInfoAndAddToTestMap(int numberOfInfos) {
+        if (numberOfInfos > 2) return;
+        for (int i = 0; i < numberOfInfos; i++) {
+            SoftApInfo info = mTestApInfo1;
+            if (i == 1) info = mTestApInfo2;
+            info.setFrequency(TEST_AP_FREQS[i]);
+            info.setBandwidth(TEST_AP_BWS[i]);
+            info.setBssid(TEST_AP_BSSIDS[i]);
+            info.setApInstanceIdentifier(TEST_AP_INSTANCES[i]);
+            mTestSoftApInfoMap.put(TEST_AP_INSTANCES[i], info);
+        }
+    }
+
+    private List<WifiClient> initWifiClientAndAddToTestMap(String targetInstance,
+            int numberOfClients, int startIdx) {
+        if (numberOfClients > 3) return null;
+        List<WifiClient> clients = new ArrayList<>();
+        for (int i = startIdx; i < startIdx + numberOfClients; i++) {
+            WifiClient client = new WifiClient(TEST_AP_CLIENTS[i], targetInstance);
+            clients.add(client);
+        }
+        mTestWifiClientsMap.put(targetInstance, clients);
+        return clients;
+    }
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -210,19 +266,160 @@
                 mRunnable.run();
             }
         };
+        mCoexCallback = new CoexCallback() {
+            @Override
+            public void onCoexUnsafeChannelsChanged() {
+                mRunnable.run();
+            }
+        };
         mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
+        mTestSoftApInfoMap.clear();
+        mTestWifiClientsMap.clear();
     }
 
     /**
+     * Check the call to setCoexUnsafeChannels calls WifiServiceImpl to setCoexUnsafeChannels with
+     * the provided CoexUnsafeChannels and restrictions bitmask.
+     */
+    @Test
+    public void testSetCoexUnsafeChannelsGoesToWifiServiceImpl() throws Exception {
+        Set<CoexUnsafeChannel> unsafeChannels = new HashSet<>();
+        int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP
+                | COEX_RESTRICTION_WIFI_AWARE;
+
+        mWifiManager.setCoexUnsafeChannels(unsafeChannels, restrictions);
+
+        verify(mWifiService).setCoexUnsafeChannels(new ArrayList<>(unsafeChannels), restrictions);
+    }
+
+    /**
+     * Verify an IllegalArgumentException if passed a null value for unsafeChannels.
+     */
+    @Test
+    public void testSetCoexUnsafeChannelsThrowsIllegalArgumentExceptionOnNullUnsafeChannels() {
+        try {
+            mWifiManager.setCoexUnsafeChannels(null, 0);
+            fail("expected IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    /**
+     * Check the call to getCoexUnsafeChannels calls WifiServiceImpl to return the values from
+     * getCoexUnsafeChannels.
+     */
+    @Test
+    public void testGetCoexUnsafeChannelsGoesToWifiServiceImpl() throws Exception {
+        Set<CoexUnsafeChannel> unsafeChannels = new HashSet<>();
+        unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6));
+        when(mWifiService.getCoexUnsafeChannels()).thenReturn(new ArrayList<>(unsafeChannels));
+
+        assertEquals(mWifiManager.getCoexUnsafeChannels(), unsafeChannels);
+    }
+
+    /**
+     * Verify call to getCoexRestrictions calls WifiServiceImpl to return the value from
+     * getCoexRestrictions.
+     */
+    @Test
+    public void testGetCoexRestrictionsGoesToWifiServiceImpl() throws Exception {
+        int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP
+                | COEX_RESTRICTION_WIFI_AWARE;
+        when(mWifiService.getCoexRestrictions()).thenReturn(restrictions);
+
+        assertEquals(mWifiService.getCoexRestrictions(), restrictions);
+    }
+
+
+    /**
+     * Verify an IllegalArgumentException is thrown if callback is not provided.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testRegisterCoexCallbackWithNullCallback() throws Exception {
+        mWifiManager.registerCoexCallback(mExecutor, null);
+    }
+
+    /**
+     * Verify an IllegalArgumentException is thrown if executor is not provided.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testRegisterCoexCallbackWithNullExecutor() throws Exception {
+        mWifiManager.registerCoexCallback(null, mCoexCallback);
+    }
+
+    /**
+     * Verify client provided callback is being called to the right callback.
+     */
+    @Test
+    public void testAddCoexCallbackAndReceiveEvent() throws Exception {
+        ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+        mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+        verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+        callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+        verify(mRunnable).run();
+    }
+
+    /**
+     * Verify client provided callback is being called to the right executor.
+     */
+    @Test
+    public void testRegisterCoexCallbackWithTheTargetExecutor() throws Exception {
+        ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+        mWifiManager.registerCoexCallback(mExecutor, mCoexCallback);
+        verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+        mWifiManager.registerCoexCallback(mAnotherExecutor, mCoexCallback);
+        callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+        verify(mExecutor, never()).execute(any(Runnable.class));
+        verify(mAnotherExecutor).execute(any(Runnable.class));
+    }
+
+    /**
+     * Verify client register unregister then register again, to ensure callback still works.
+     */
+    @Test
+    public void testRegisterUnregisterThenRegisterAgainWithCoexCallback() throws Exception {
+        ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+        mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+        verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+        mWifiManager.unregisterCoexCallback(mCoexCallback);
+        callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+        verify(mRunnable, never()).run();
+        mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+        callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+        verify(mRunnable).run();
+    }
+
+    /**
+     * Verify client unregisterCoexCallback.
+     */
+    @Test
+    public void testUnregisterCoexCallback() throws Exception {
+        mWifiManager.unregisterCoexCallback(mCoexCallback);
+        verify(mWifiService).unregisterCoexCallback(any());
+    }
+
+    /**
+     * Verify client unregisterCoexCallback with null callback will cause an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testUnregisterCoexCallbackWithNullCallback() throws Exception {
+        mWifiManager.unregisterCoexCallback(null);
+    }
+
+
+    /**
      * Check the call to startSoftAp calls WifiService to startSoftAp with the provided
      * WifiConfiguration.  Verify that the return value is propagated to the caller.
      */
     @Test
     public void testStartSoftApCallsServiceWithWifiConfig() throws Exception {
-        when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(true);
+        when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(true);
         assertTrue(mWifiManager.startSoftAp(mApConfig));
 
-        when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(false);
+        when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(false);
         assertFalse(mWifiManager.startSoftAp(mApConfig));
     }
 
@@ -232,10 +429,10 @@
      */
     @Test
     public void testStartSoftApCallsServiceWithNullConfig() throws Exception {
-        when(mWifiService.startSoftAp(eq(null))).thenReturn(true);
+        when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(true);
         assertTrue(mWifiManager.startSoftAp(null));
 
-        when(mWifiService.startSoftAp(eq(null))).thenReturn(false);
+        when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(false);
         assertFalse(mWifiManager.startSoftAp(null));
     }
 
@@ -258,10 +455,12 @@
     @Test
     public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception {
         SoftApConfiguration softApConfig = generatorTestSoftApConfig();
-        when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(true);
+        when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME))
+                .thenReturn(true);
         assertTrue(mWifiManager.startTetheredHotspot(softApConfig));
 
-        when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(false);
+        when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME))
+                .thenReturn(false);
         assertFalse(mWifiManager.startTetheredHotspot(softApConfig));
     }
 
@@ -271,10 +470,10 @@
      */
     @Test
     public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception {
-        when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true);
+        when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(true);
         assertTrue(mWifiManager.startTetheredHotspot(null));
 
-        when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false);
+        when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(false);
         assertFalse(mWifiManager.startTetheredHotspot(null));
     }
 
@@ -930,11 +1129,149 @@
         mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
-
-        final List<WifiClient> testClients = new ArrayList();
-        callbackCaptor.getValue().onConnectedClientsChanged(testClients);
+        List<WifiClient> clientList;
+        // Verify the register callback in disable state.
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, true);
         mLooper.dispatchAll();
-        verify(mSoftApCallback).onConnectedClientsChanged(testClients);
+        verify(mSoftApCallback).onConnectedClientsChanged(new ArrayList<WifiClient>());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        verify(mSoftApCallback).onInfoChanged(new SoftApInfo());
+        verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Single AP mode Test
+        // Test info update
+        initTestInfoAndAddToTestMap(1);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback).onInfoChanged(mTestApInfo1);
+        verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
+                        infos.contains(mTestApInfo1)));
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test first client connected
+        clientList = initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[0], 1, 0);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
+        mLooper.dispatchAll();
+        // checked NO any infoChanged, includes InfoChanged(SoftApInfo)
+        // and InfoChanged(List<SoftApInfo>)
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback, never()).onInfoChanged(any(List.class));
+        verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo1, clientList);
+        verify(mSoftApCallback).onConnectedClientsChanged(clientList);
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test second client connected
+        mTestWifiClientsMap.clear();
+        clientList = initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[0], 2, 0);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
+        mLooper.dispatchAll();
+        // checked NO any infoChanged, includes InfoChanged(SoftApInfo)
+        // and InfoChanged(List<SoftApInfo>)
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback, never()).onInfoChanged(any(List.class));
+        verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo1, clientList);
+        verify(mSoftApCallback).onConnectedClientsChanged(clientList);
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test second client disconnect
+        mTestWifiClientsMap.clear();
+        clientList = initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[0], 1, 0);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
+        mLooper.dispatchAll();
+        // checked NO any infoChanged, includes InfoChanged(SoftApInfo)
+        // and InfoChanged(List<SoftApInfo>)
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback, never()).onInfoChanged(any(List.class));
+        verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo1, clientList);
+        verify(mSoftApCallback).onConnectedClientsChanged(clientList);
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test bridged mode case
+        mTestSoftApInfoMap.clear();
+        initTestInfoAndAddToTestMap(2);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
+                  infos.contains(mTestApInfo1) && infos.contains(mTestApInfo2)
+                  ));
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test client connect to second instance
+        List<WifiClient> clientListOnSecond =
+                initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[1], 1, 2); // client3 to wlan2
+        List<WifiClient> totalList = new ArrayList<>();
+        totalList.addAll(clientList);
+        totalList.addAll(clientListOnSecond);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
+        mLooper.dispatchAll();
+        // checked NO any infoChanged, includes InfoChanged(SoftApInfo)
+        // and InfoChanged(List<SoftApInfo>)
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback, never()).onInfoChanged(any(List.class));
+        verify(mSoftApCallback).onConnectedClientsChanged(mTestApInfo2, clientListOnSecond);
+        verify(mSoftApCallback).onConnectedClientsChanged(totalList);
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test shutdown on second instance
+        mTestSoftApInfoMap.clear();
+        mTestWifiClientsMap.clear();
+        initTestInfoAndAddToTestMap(1);
+        clientList = initWifiClientAndAddToTestMap(TEST_AP_INSTANCES[0], 1, 0);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
+                        infos.contains(mTestApInfo1)));
+        // second instance have client connected before, thus it should send empty list
+        verify(mSoftApCallback).onConnectedClientsChanged(
+                mTestApInfo2, new ArrayList<WifiClient>());
+        verify(mSoftApCallback).onConnectedClientsChanged(clientList);
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test bridged mode disable when client connected
+        mTestSoftApInfoMap.clear();
+        mTestWifiClientsMap.clear();
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
+        verify(mSoftApCallback).onConnectedClientsChanged(new ArrayList<WifiClient>());
+        verify(mSoftApCallback).onConnectedClientsChanged(
+                mTestApInfo1, new ArrayList<WifiClient>());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
     }
 
 
@@ -943,20 +1280,139 @@
      */
     @Test
     public void softApCallbackProxyCallsOnSoftApInfoChanged() throws Exception {
-        SoftApInfo testSoftApInfo = new SoftApInfo();
-        testSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
-        testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
+        ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
+        verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
+                anyInt());
+        // Verify the register callback in disable state.
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, true);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback).onConnectedClientsChanged(new ArrayList<WifiClient>());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        verify(mSoftApCallback).onInfoChanged(new SoftApInfo());
+        verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Single AP mode Test
+        // Test info update
+        initTestInfoAndAddToTestMap(1);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback).onInfoChanged(mTestApInfo1);
+        verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
+                        infos.contains(mTestApInfo1)));
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test info changed
+        SoftApInfo changedInfo = new SoftApInfo(mTestSoftApInfoMap.get(TEST_AP_INSTANCES[0]));
+        changedInfo.setFrequency(2422);
+        mTestSoftApInfoMap.put(TEST_AP_INSTANCES[0], changedInfo);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback).onInfoChanged(changedInfo);
+        verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
+                        infos.contains(changedInfo)));
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+
+        // Test Stop, all of infos is empty
+        mTestSoftApInfoMap.clear();
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), false, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback).onInfoChanged(new SoftApInfo());
+        verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+    }
+
+    /*
+     * Verify client-provided callback is being called through callback proxy
+     */
+    @Test
+    public void softApCallbackProxyCallsOnSoftApInfoChangedInBridgedMode() throws Exception {
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
         mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
-        callbackCaptor.getValue().onInfoChanged(testSoftApInfo);
+        // Test bridged mode case
+        initTestInfoAndAddToTestMap(2);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
         mLooper.dispatchAll();
-        verify(mSoftApCallback).onInfoChanged(testSoftApInfo);
-    }
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
+                  infos.contains(mTestApInfo1) && infos.contains(mTestApInfo2)
+                  ));
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
 
+        // Test bridged mode case but an info changed
+        SoftApInfo changedInfoBridgedMode = new SoftApInfo(mTestSoftApInfoMap.get(
+                TEST_AP_INSTANCES[0]));
+        changedInfoBridgedMode.setFrequency(2422);
+        mTestSoftApInfoMap.put(TEST_AP_INSTANCES[0], changedInfoBridgedMode);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
+                  infos.contains(changedInfoBridgedMode) && infos.contains(mTestApInfo2)
+                  ));
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test bridged mode case but an instance shutdown
+        mTestSoftApInfoMap.clear();
+        initTestInfoAndAddToTestMap(1);
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback).onInfoChanged(Mockito.argThat((List<SoftApInfo> infos) ->
+                  infos.contains(mTestApInfo1)
+                  ));
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+
+        // Test bridged mode disable case
+        mTestSoftApInfoMap.clear();
+        callbackCaptor.getValue().onConnectedClientsOrInfoChanged(
+                (Map<String, SoftApInfo>) mTestSoftApInfoMap.clone(),
+                (Map<String, List<WifiClient>>) mTestWifiClientsMap.clone(), true, false);
+        mLooper.dispatchAll();
+        verify(mSoftApCallback, never()).onInfoChanged(any(SoftApInfo.class));
+        verify(mSoftApCallback).onInfoChanged(new ArrayList<SoftApInfo>());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any());
+        verify(mSoftApCallback, never()).onConnectedClientsChanged(any(), any());
+        // After verify, reset mSoftApCallback for nex test
+        reset(mSoftApCallback);
+    }
 
     /*
      * Verify client-provided callback is being called through callback proxy
@@ -981,7 +1437,8 @@
      */
     @Test
     public void softApCallbackProxyCallsOnBlockedClientConnecting() throws Exception {
-        WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77"));
+        WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77"),
+                TEST_AP_INSTANCES[0]);
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
         mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
@@ -1000,9 +1457,6 @@
      */
     @Test
     public void softApCallbackProxyCallsOnMultipleUpdates() throws Exception {
-        SoftApInfo testSoftApInfo = new SoftApInfo();
-        testSoftApInfo.setFrequency(TEST_AP_FREQUENCY);
-        testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
         SoftApCapability testSoftApCapability = new SoftApCapability(0);
         testSoftApCapability.setMaxSupportedClients(10);
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
@@ -1013,16 +1467,12 @@
 
         final List<WifiClient> testClients = new ArrayList();
         callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLING, 0);
-        callbackCaptor.getValue().onConnectedClientsChanged(testClients);
-        callbackCaptor.getValue().onInfoChanged(testSoftApInfo);
         callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
         callbackCaptor.getValue().onCapabilityChanged(testSoftApCapability);
 
 
         mLooper.dispatchAll();
         verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLING, 0);
-        verify(mSoftApCallback).onConnectedClientsChanged(testClients);
-        verify(mSoftApCallback).onInfoChanged(testSoftApInfo);
         verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
         verify(mSoftApCallback).onCapabilityChanged(testSoftApCapability);
     }
@@ -1628,6 +2078,24 @@
     }
 
     /**
+     * Verify the call to startTemporarilyDisablingAllNonCarrierMergedWifi goes to WifiServiceImpl.
+     */
+    @Test
+    public void testStartTemporarilyDisablingAllNonCarrierMergedWifi() throws Exception {
+        mWifiManager.startTemporarilyDisablingAllNonCarrierMergedWifi(1);
+        verify(mWifiService).startTemporarilyDisablingAllNonCarrierMergedWifi(1);
+    }
+
+    /**
+     * Verify the call to stopTemporarilyDisablingAllNonCarrierMergedWifi goes to WifiServiceImpl.
+     */
+    @Test
+    public void testStopTemporarilyDisablingAllNonCarrierMergedWifi() throws Exception {
+        mWifiManager.stopTemporarilyDisablingAllNonCarrierMergedWifi();
+        verify(mWifiService).stopTemporarilyDisablingAllNonCarrierMergedWifi();
+    }
+
+    /**
      * Verify the call to addOnWifiUsabilityStatsListener goes to WifiServiceImpl.
      */
     @Test
@@ -1707,6 +2175,34 @@
     }
 
     /**
+     * Test behavior of isStaApConcurrencySupported
+     */
+    @Test
+    public void testIsStaApConcurrencyOpenSupported() throws Exception {
+        when(mWifiService.getSupportedFeatures())
+                .thenReturn(new Long(WIFI_FEATURE_AP_STA));
+        assertTrue(mWifiManager.isStaApConcurrencySupported());
+        when(mWifiService.getSupportedFeatures())
+                .thenReturn(new Long(~WIFI_FEATURE_AP_STA));
+        assertFalse(mWifiManager.isStaApConcurrencySupported());
+    }
+
+    /**
+     * Test behavior of isMultiStaConcurrencySupported
+     */
+    @Test
+    public void testIsMultiStaConcurrencyOpenSupported() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        when(mWifiService.getSupportedFeatures())
+                .thenReturn(new Long(WIFI_FEATURE_ADDITIONAL_STA));
+        assertTrue(mWifiManager.isMultiStaConcurrencySupported());
+        when(mWifiService.getSupportedFeatures())
+                .thenReturn(new Long(~WIFI_FEATURE_ADDITIONAL_STA));
+        assertFalse(mWifiManager.isMultiStaConcurrencySupported());
+    }
+
+    /**
      * Test behavior of {@link WifiManager#addNetwork(WifiConfiguration)}
      */
     @Test
@@ -1857,7 +2353,6 @@
         assertFalse(mWifiManager.isDeviceToDeviceRttSupported());
         assertFalse(mWifiManager.isDeviceToApRttSupported());
         assertFalse(mWifiManager.isPreferredNetworkOffloadSupported());
-        assertFalse(mWifiManager.isAdditionalStaSupported());
         assertFalse(mWifiManager.isTdlsSupported());
         assertFalse(mWifiManager.isOffChannelTdlsSupported());
         assertFalse(mWifiManager.isEnhancedPowerReportingSupported());
@@ -1992,8 +2487,7 @@
 
         ArgumentCaptor<IActionListener> binderListenerCaptor =
                 ArgumentCaptor.forClass(IActionListener.class);
-        verify(mWifiService).connect(eq(null), eq(TEST_NETWORK_ID), any(Binder.class),
-                binderListenerCaptor.capture(), anyInt());
+        verify(mWifiService).connect(eq(null), eq(TEST_NETWORK_ID), binderListenerCaptor.capture());
         assertNotNull(binderListenerCaptor.getValue());
 
         // Trigger on success.
@@ -2013,8 +2507,7 @@
     @Test
     public void testConnectWithListenerHandleSecurityException() throws Exception {
         doThrow(new SecurityException()).when(mWifiService)
-                .connect(eq(null), anyInt(), any(IBinder.class),
-                        any(IActionListener.class), anyInt());
+                .connect(eq(null), anyInt(), any(IActionListener.class));
         ActionListener externalListener = mock(ActionListener.class);
         mWifiManager.connect(TEST_NETWORK_ID, externalListener);
 
@@ -2028,8 +2521,7 @@
     @Test
     public void testConnectWithListenerHandleRemoteException() throws Exception {
         doThrow(new RemoteException()).when(mWifiService)
-                .connect(eq(null), anyInt(), any(IBinder.class),
-                        any(IActionListener.class), anyInt());
+                .connect(eq(null), anyInt(), any(IActionListener.class));
         ActionListener externalListener = mock(ActionListener.class);
         mWifiManager.connect(TEST_NETWORK_ID, externalListener);
 
@@ -2045,8 +2537,7 @@
         WifiConfiguration configuration = new WifiConfiguration();
         mWifiManager.connect(configuration, null);
 
-        verify(mWifiService).connect(configuration, WifiConfiguration.INVALID_NETWORK_ID, null,
-                null, 0);
+        verify(mWifiService).connect(configuration, WifiConfiguration.INVALID_NETWORK_ID, null);
     }
 
     /**
@@ -2132,7 +2623,7 @@
      */
     @Test(expected = IllegalArgumentException.class)
     public void testAddSuggestionConnectionStatusListenerWithNullExecutor() {
-        mWifiManager.addSuggestionConnectionStatusListener(null, mListener);
+        mWifiManager.addSuggestionConnectionStatusListener(null, mSuggestionConnectionListener);
     }
 
     /**
@@ -2152,11 +2643,12 @@
         ArgumentCaptor<ISuggestionConnectionStatusListener.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISuggestionConnectionStatusListener.Stub.class);
         Executor executor = new SynchronousExecutor();
-        mWifiManager.addSuggestionConnectionStatusListener(executor, mListener);
+        mWifiManager.addSuggestionConnectionStatusListener(executor, mSuggestionConnectionListener);
         verify(mWifiService).registerSuggestionConnectionStatusListener(any(IBinder.class),
                 callbackCaptor.capture(), anyInt(), anyString(), nullable(String.class));
         callbackCaptor.getValue().onConnectionStatus(mWifiNetworkSuggestion, errorCode);
-        verify(mListener).onConnectionStatus(any(WifiNetworkSuggestion.class), eq(errorCode));
+        verify(mSuggestionConnectionListener).onConnectionStatus(any(WifiNetworkSuggestion.class),
+                eq(errorCode));
     }
 
     /**
@@ -2167,7 +2659,8 @@
         int errorCode = STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
         ArgumentCaptor<ISuggestionConnectionStatusListener.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISuggestionConnectionStatusListener.Stub.class);
-        mWifiManager.addSuggestionConnectionStatusListener(mExecutor, mListener);
+        mWifiManager.addSuggestionConnectionStatusListener(mExecutor,
+                mSuggestionConnectionListener);
         verify(mWifiService).registerSuggestionConnectionStatusListener(any(IBinder.class),
                 callbackCaptor.capture(), anyInt(), anyString(), nullable(String.class));
         callbackCaptor.getValue().onConnectionStatus(any(WifiNetworkSuggestion.class), errorCode);
@@ -2187,7 +2680,7 @@
      */
     @Test
     public void testRemoveSuggestionConnectionListener() throws Exception {
-        mWifiManager.removeSuggestionConnectionStatusListener(mListener);
+        mWifiManager.removeSuggestionConnectionStatusListener(mSuggestionConnectionListener);
         verify(mWifiService).unregisterSuggestionConnectionStatusListener(anyInt(), anyString());
     }
 
@@ -2380,10 +2873,118 @@
     @Test
     public void testScanAvailable() throws Exception {
         mWifiManager.setScanAlwaysAvailable(true);
-        verify(mWifiService).setScanAlwaysAvailable(true);
+        verify(mWifiService).setScanAlwaysAvailable(true, TEST_PACKAGE_NAME);
 
         when(mWifiService.isScanAlwaysAvailable()).thenReturn(false);
         assertFalse(mWifiManager.isScanAlwaysAvailable());
         verify(mWifiService).isScanAlwaysAvailable();
     }
+
+    @Test
+    public void testGetNetworkSuggestionUserApprovalStatus() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        when(mWifiService.getNetworkSuggestionUserApprovalStatus(TEST_PACKAGE_NAME))
+                .thenReturn(WifiManager.STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER);
+        assertEquals(WifiManager.STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER,
+                mWifiManager.getNetworkSuggestionUserApprovalStatus());
+        verify(mWifiService).getNetworkSuggestionUserApprovalStatus(TEST_PACKAGE_NAME);
+    }
+
+    @Test
+    public void testSetCarrierNetworkOffload() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        mWifiManager.setCarrierNetworkOffloadEnabled(TEST_SUB_ID, true, false);
+        verify(mWifiService).setCarrierNetworkOffloadEnabled(TEST_SUB_ID,
+                true, false);
+    }
+
+    @Test
+    public void testGetCarrierNetworkOffload() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        when(mWifiService.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false)).thenReturn(true);
+        assertTrue(mWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false));
+        verify(mWifiService).isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false);
+    }
+
+
+    /**
+     * Verify an IllegalArgumentException is thrown if listener is not provided.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testRemoveSuggestionUserApprovalStatusListenerWithNullListener() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        mWifiManager.removeSuggestionUserApprovalStatusListener(null);
+    }
+
+
+    /**
+     * Verify removeSuggestionUserApprovalStatusListener.
+     */
+    @Test
+    public void testRemoveSuggestionUserApprovalStatusListener() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        mWifiManager.removeSuggestionUserApprovalStatusListener(
+                mSuggestionUserApprovalStatusListener);
+        verify(mWifiService).removeSuggestionUserApprovalStatusListener(anyInt(), anyString());
+    }
+
+    /**
+     * Verify an IllegalArgumentException is thrown if executor not provided.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testAddSuggestionUserApprovalStatusListenerWithNullExecutor() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        mWifiManager.addSuggestionUserApprovalStatusListener(null,
+                mSuggestionUserApprovalStatusListener);
+    }
+
+    /**
+     * Verify an IllegalArgumentException is thrown if listener is not provided.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testAddSuggestionUserApprovalStatusListenerWithNullListener() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        mWifiManager.addSuggestionUserApprovalStatusListener(mExecutor, null);
+    }
+
+    /**
+     * Verify client provided listener is being called to the right listener.
+     */
+    @Test
+    public void testAddSuggestionUserApprovalStatusListenerAndReceiveEvent() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        ArgumentCaptor<ISuggestionUserApprovalStatusListener.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ISuggestionUserApprovalStatusListener.Stub.class);
+        Executor executor = new SynchronousExecutor();
+        mWifiManager.addSuggestionUserApprovalStatusListener(executor,
+                mSuggestionUserApprovalStatusListener);
+        verify(mWifiService).addSuggestionUserApprovalStatusListener(any(IBinder.class),
+                callbackCaptor.capture(), anyInt(), anyString(), nullable(String.class));
+        callbackCaptor.getValue().onUserApprovalStatusChange();
+        verify(mSuggestionUserApprovalStatusListener).onUserApprovalStatusChange();
+    }
+
+    /**
+     * Verify client provided listener is being called to the right executor.
+     */
+    @Test
+    public void testAddSuggestionUserApprovalStatusListenerWithTheTargetExecutor()
+            throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        ArgumentCaptor<ISuggestionUserApprovalStatusListener.Stub> callbackCaptor =
+                ArgumentCaptor.forClass(ISuggestionUserApprovalStatusListener.Stub.class);
+        mWifiManager.addSuggestionUserApprovalStatusListener(mExecutor,
+                mSuggestionUserApprovalStatusListener);
+        verify(mWifiService).addSuggestionUserApprovalStatusListener(any(IBinder.class),
+                callbackCaptor.capture(), anyInt(), anyString(), nullable(String.class));
+        callbackCaptor.getValue().onUserApprovalStatusChange();
+        verify(mExecutor).execute(any(Runnable.class));
+    }
+
 }
diff --git a/framework/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/framework/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index 6f47f3d..464f462 100644
--- a/framework/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/framework/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -141,11 +141,11 @@
     }
 
     /**
-     * Validate correctness of WifiNetworkSuggestion object created by
-     * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise network.
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkSpecifier.Builder#build()} for WPA3-Enterprise network.
      */
     @Test
-    public void testWifiNetworkSuggestionBuilderForWpa3EapNetwork() {
+    public void testWifiNetworkSpecifierBuilderForWpa3EapNetwork() {
         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
         enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
         enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
@@ -174,11 +174,118 @@
     }
 
     /**
-     * Validate correctness of WifiNetworkSuggestion object created by
-     * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise 192-bit RSA SuiteB network.
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkSpecifier.Builder#build()} for WPA3-Enterprise network.
      */
     @Test
-    public void testWifiNetworkSuggestionBuilderForWpa3SuiteBRsaEapNetwork() {
+    public void testWifiNetworkSpecifierBuilderForWpa3EapNetworkWithStandardApi() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        NetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3EnterpriseStandardModeConfig(enterpriseConfig)
+                .build();
+
+        assertTrue(specifier instanceof WifiNetworkSpecifier);
+        WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+        assertEquals("\"" + TEST_SSID + "\"", wifiNetworkSpecifier.wifiConfiguration.SSID);
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertFalse(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.requirePmf);
+        assertNull(wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+        assertNotNull(wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig);
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkSpecifier.Builder#build()} for WPA3-Enterprise network
+     * with 192-bit RSA certificates.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBuilderForWpa3EapNetworkWithSuiteBRsaCerts() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_RSA3072_CERT);
+        enterpriseConfig.setClientKeyEntryWithCertificateChain(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY,
+                new X509Certificate[] {FakeKeys.CLIENT_SUITE_B_RSA3072_CERT});
+
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        NetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3EnterpriseStandardModeConfig(enterpriseConfig)
+                .build();
+
+        assertTrue(specifier instanceof WifiNetworkSpecifier);
+        WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+        assertEquals("\"" + TEST_SSID + "\"", wifiNetworkSpecifier.wifiConfiguration.SSID);
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertFalse(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.requirePmf);
+        assertNull(wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+        assertNotNull(wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig);
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkSpecifier.Builder#build()} for WPA3-Enterprise network
+     * with 192-bit ECC certificates.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBuilderForWpa3EapNetworkWithSuiteBEccCerts() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_ECDSA_CERT);
+        enterpriseConfig.setClientKeyEntryWithCertificateChain(FakeKeys.CLIENT_SUITE_B_ECC_KEY,
+                new X509Certificate[] {FakeKeys.CLIENT_SUITE_B_ECDSA_CERT});
+
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        NetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3EnterpriseStandardModeConfig(enterpriseConfig)
+                .build();
+
+        assertTrue(specifier instanceof WifiNetworkSpecifier);
+        WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+        assertEquals("\"" + TEST_SSID + "\"", wifiNetworkSpecifier.wifiConfiguration.SSID);
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertFalse(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.requirePmf);
+        assertNull(wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+        assertNotNull(wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig);
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkSpecifier.Builder#build()} for WPA3-Enterprise 192-bit RSA SuiteB network.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBuilderForWpa3SuiteBRsaEapNetwork() {
         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
         enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
         enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_RSA3072_CERT);
@@ -208,11 +315,11 @@
     }
 
     /**
-     * Validate correctness of WifiNetworkSuggestion object created by
-     * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise 192-bit ECC SuiteB network.
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkSpecifier.Builder#build()} for WPA3-Enterprise 192-bit ECC SuiteB network.
      */
     @Test
-    public void testWifiNetworkSuggestionBuilderForWpa3SuiteBEccEapNetwork() {
+    public void testWifiNetworkSpecifierBuilderForWpa3SuiteBEccEapNetwork() {
         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
         enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
         enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_ECDSA_CERT);
@@ -242,6 +349,74 @@
     }
 
     /**
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkSpecifier.Builder#build()} for WPA3-Enterprise 192-bit RSA SuiteB network.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBuilderForWpa3SuiteBRsaEapNetworkWith192BitApi() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_RSA3072_CERT);
+        enterpriseConfig.setClientKeyEntryWithCertificateChain(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY,
+                new X509Certificate[] {FakeKeys.CLIENT_SUITE_B_RSA3072_CERT});
+
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        NetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3Enterprise192BitModeConfig(enterpriseConfig)
+                .build();
+
+        assertTrue(specifier instanceof WifiNetworkSpecifier);
+        WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+        assertEquals("\"" + TEST_SSID + "\"", wifiNetworkSpecifier.wifiConfiguration.SSID);
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.GCMP_256));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupManagementCiphers
+                .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.requirePmf);
+        assertNull(wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+        assertNotNull(wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig);
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSpecifier object created by
+     * {@link WifiNetworkSpecifier.Builder#build()} for WPA3-Enterprise 192-bit ECC SuiteB network.
+     */
+    @Test
+    public void testWifiNetworkSpecifierBuilderForWpa3SuiteBEccEapNetworkWith192BitApi() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_ECDSA_CERT);
+        enterpriseConfig.setClientKeyEntryWithCertificateChain(FakeKeys.CLIENT_SUITE_B_ECC_KEY,
+                new X509Certificate[] {FakeKeys.CLIENT_SUITE_B_ECDSA_CERT});
+
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        NetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3Enterprise192BitModeConfig(enterpriseConfig)
+                .build();
+
+        assertTrue(specifier instanceof WifiNetworkSpecifier);
+        WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+        assertEquals("\"" + TEST_SSID + "\"", wifiNetworkSpecifier.wifiConfiguration.SSID);
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.GCMP_256));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupManagementCiphers
+                .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+        assertTrue(wifiNetworkSpecifier.wifiConfiguration.requirePmf);
+        assertNull(wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+        assertNotNull(wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig);
+    }
+
+    /**
      * Ensure {@link WifiNetworkSpecifier.Builder#setSsid(String)} throws an exception
      * when the string is not Unicode.
      */
@@ -430,15 +605,16 @@
     /**
      * Ensure {@link WifiNetworkSpecifier.Builder#build()} throws an exception
      * when both {@link WifiNetworkSpecifier.Builder#setWpa3Passphrase(String)} and
-     * {@link WifiNetworkSpecifier.Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)} are
-     * invoked.
+     * {@link WifiNetworkSpecifier.Builder
+     * #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)}
+     * are invoked.
      */
     @Test(expected = IllegalStateException.class)
     public void testWifiNetworkSpecifierBuilderWithBothWpa3PasphraseAndEnterprise() {
         new WifiNetworkSpecifier.Builder()
                 .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
                 .setWpa3Passphrase(TEST_PRESHARED_KEY)
-                .setWpa3EnterpriseConfig(new WifiEnterpriseConfig())
+                .setWpa3EnterpriseStandardModeConfig(new WifiEnterpriseConfig())
                 .build();
     }
 
diff --git a/framework/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/framework/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 00a0442..5e82918 100644
--- a/framework/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/framework/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -16,7 +16,13 @@
 
 package android.net.wifi;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.net.MacAddress;
 import android.net.wifi.hotspot2.PasspointConfiguration;
@@ -25,6 +31,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import org.junit.Test;
 
 import java.security.cert.X509Certificate;
@@ -41,6 +49,8 @@
     private static final String TEST_FQDN = "fqdn";
     private static final String TEST_WAPI_CERT_SUITE = "suite";
     private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
+    private static final int DEFAULT_PRIORITY_GROUP = 0;
+    private static final int TEST_PRIORITY_GROUP = 1;
 
     /**
      * Validate correctness of WifiNetworkSuggestion object created by
@@ -64,6 +74,7 @@
         assertEquals(-1, suggestion.wifiConfiguration.priority);
         assertFalse(suggestion.isUserAllowedToManuallyConnect);
         assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -94,6 +105,7 @@
         assertEquals(0, suggestion.wifiConfiguration.priority);
         assertFalse(suggestion.isUserAllowedToManuallyConnect);
         assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -124,6 +136,7 @@
         assertEquals(-1, suggestion.wifiConfiguration.priority);
         assertTrue(suggestion.isUserAllowedToManuallyConnect);
         assertFalse(suggestion.isInitialAutoJoinEnabled);
+        assertNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -154,6 +167,7 @@
         assertEquals(-1, suggestion.wifiConfiguration.priority);
         assertTrue(suggestion.isUserAllowedToManuallyConnect);
         assertFalse(suggestion.isInitialAutoJoinEnabled);
+        assertNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -176,6 +190,63 @@
         assertTrue(suggestion.wifiConfiguration.requirePmf);
         assertFalse(suggestion.isUserAllowedToManuallyConnect);
         assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNull(suggestion.getEnterpriseConfig());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for OWE network.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForOemPaidEnhancedOpenNetworkWithBssid() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setBssid(MacAddress.fromString(TEST_BSSID))
+                .setOemPaid(true)
+                .setIsEnhancedOpen(true)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertEquals(TEST_BSSID, suggestion.wifiConfiguration.BSSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.OWE));
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        assertTrue(suggestion.wifiConfiguration.requirePmf);
+        assertTrue(suggestion.wifiConfiguration.oemPaid);
+        assertTrue(suggestion.isOemPaid());
+        assertFalse(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNull(suggestion.getEnterpriseConfig());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for OWE network.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForOemPrivateEnhancedOpenNetworkWithBssid() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setBssid(MacAddress.fromString(TEST_BSSID))
+                .setOemPrivate(true)
+                .setIsEnhancedOpen(true)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertEquals(TEST_BSSID, suggestion.wifiConfiguration.BSSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.OWE));
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        assertTrue(suggestion.wifiConfiguration.requirePmf);
+        assertTrue(suggestion.wifiConfiguration.oemPrivate);
+        assertTrue(suggestion.isOemPrivate());
+        assertFalse(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -199,6 +270,7 @@
         assertTrue(suggestion.wifiConfiguration.requirePmf);
         assertTrue(suggestion.isUserAllowedToManuallyConnect);
         assertFalse(suggestion.isInitialAutoJoinEnabled);
+        assertNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -237,6 +309,116 @@
 
     /**
      * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise standard network.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWpa3EapNetworkWithStandardApi() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3EnterpriseStandardModeConfig(enterpriseConfig)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertFalse(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(suggestion.wifiConfiguration.requirePmf);
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        // allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
+        // here.
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNotNull(suggestion.getEnterpriseConfig());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise network
+     * with 192-bit RSA SuiteB certificates.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWpa3EapNetworkWithSuiteBRsaCerts() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_RSA3072_CERT);
+        enterpriseConfig.setClientKeyEntryWithCertificateChain(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY,
+                new X509Certificate[] {FakeKeys.CLIENT_SUITE_B_RSA3072_CERT});
+
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3EnterpriseStandardModeConfig(enterpriseConfig)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertFalse(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(suggestion.wifiConfiguration.requirePmf);
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        // allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
+        // here.
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNotNull(suggestion.getEnterpriseConfig());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise network
+     * with 192-bit ECC certificates.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWpa3EapNetworkWithSuiteBEccCerts() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_ECDSA_CERT);
+        enterpriseConfig.setClientKeyEntryWithCertificateChain(FakeKeys.CLIENT_SUITE_B_ECC_KEY,
+                new X509Certificate[] {FakeKeys.CLIENT_SUITE_B_ECDSA_CERT});
+
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3EnterpriseStandardModeConfig(enterpriseConfig)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertFalse(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(suggestion.wifiConfiguration.requirePmf);
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        // allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
+        // here.
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNotNull(suggestion.getEnterpriseConfig());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
      * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise 192-bit RSA SuiteB network.
      */
     @Test
@@ -272,6 +454,41 @@
 
     /**
      * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise 192-bit RSA SuiteB network.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWpa3SuiteBRsaEapNetworWith192BitApi() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_RSA3072_CERT);
+        enterpriseConfig.setClientKeyEntryWithCertificateChain(FakeKeys.CLIENT_SUITE_B_RSA3072_KEY,
+                new X509Certificate[] {FakeKeys.CLIENT_SUITE_B_RSA3072_CERT});
+
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3Enterprise192BitModeConfig(enterpriseConfig)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.GCMP_256));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupManagementCiphers
+                .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+        assertTrue(suggestion.wifiConfiguration.requirePmf);
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        // allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
+        // here.
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNotNull(suggestion.getEnterpriseConfig());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
      * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise 192-bit ECC SuiteB network.
      */
     @Test
@@ -302,6 +519,42 @@
         // here.
         assertTrue(suggestion.isUserAllowedToManuallyConnect);
         assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNotNull(suggestion.getEnterpriseConfig());
+    }
+
+    /**
+     * Validate correctness of WifiNetworkSuggestion object created by
+     * {@link WifiNetworkSuggestion.Builder#build()} for WPA3-Enterprise 192-bit ECC SuiteB network.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderForWpa3SuiteBEccEapNetworkWith192BitApi() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_SUITE_B_ECDSA_CERT);
+        enterpriseConfig.setClientKeyEntryWithCertificateChain(FakeKeys.CLIENT_SUITE_B_ECC_KEY,
+                new X509Certificate[] {FakeKeys.CLIENT_SUITE_B_ECDSA_CERT});
+
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa3Enterprise192BitModeConfig(enterpriseConfig)
+                .build();
+
+        assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+        assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+                .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+                .get(WifiConfiguration.GroupCipher.GCMP_256));
+        assertTrue(suggestion.wifiConfiguration.allowedGroupManagementCiphers
+                .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+        assertTrue(suggestion.wifiConfiguration.requirePmf);
+        assertNull(suggestion.wifiConfiguration.preSharedKey);
+        // allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
+        // here.
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.isInitialAutoJoinEnabled);
+        assertNotNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -334,7 +587,7 @@
 
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
-                .setWpa3EnterpriseConfig(enterpriseConfig)
+                .setWpa3EnterpriseStandardModeConfig(enterpriseConfig)
                 .build();
     }
 
@@ -358,6 +611,7 @@
                 .get(WifiConfiguration.GroupCipher.SMS4));
         assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
                 suggestion.wifiConfiguration.preSharedKey);
+        assertNull(suggestion.getEnterpriseConfig());
     }
 
 
@@ -388,6 +642,7 @@
                 suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
         assertEquals(TEST_WAPI_CERT_SUITE,
                 suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+        assertNotNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -417,6 +672,7 @@
                 suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
         assertEquals("",
                 suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+        assertNotNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -439,6 +695,7 @@
         assertEquals(suggestion.getPasspointConfig().getMeteredOverride(),
                 WifiConfiguration.METERED_OVERRIDE_METERED);
         assertTrue(suggestion.isUserAllowedToManuallyConnect);
+        assertNull(suggestion.getEnterpriseConfig());
     }
 
     /**
@@ -552,15 +809,16 @@
     /**
      * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
      * when both {@link WifiNetworkSuggestion.Builder#setWpa3Passphrase(String)} and
-     * {@link WifiNetworkSuggestion.Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)} are
-     * invoked.
+     * {@link WifiNetworkSuggestion.Builder
+     * #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)}
+     * are invoked.
      */
     @Test(expected = IllegalStateException.class)
     public void testWifiNetworkSuggestionBuilderWithBothWpa3PasphraseAndEnterprise() {
         new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
                 .setWpa3Passphrase(TEST_PRESHARED_KEY)
-                .setWpa3EnterpriseConfig(new WifiEnterpriseConfig())
+                .setWpa3EnterpriseStandardModeConfig(new WifiEnterpriseConfig())
                 .build();
     }
 
@@ -622,7 +880,9 @@
 
     /**
      * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
-     * when both {@link WifiNetworkSuggestion.Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)}
+     * when both
+     * {@link WifiNetworkSuggestion.Builder
+     * #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)}
      * and {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} are
      * invoked.
      */
@@ -630,7 +890,7 @@
     public void testWifiNetworkSuggestionBuilderWithBothEnterpriseAndPasspointConfig() {
         PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
         new WifiNetworkSuggestion.Builder()
-                .setWpa3EnterpriseConfig(new WifiEnterpriseConfig())
+                .setWpa3EnterpriseStandardModeConfig(new WifiEnterpriseConfig())
                 .setPasspointConfig(passpointConfiguration)
                 .build();
     }
@@ -664,6 +924,84 @@
     }
 
     /**
+     * Verify that the macRandomizationSetting defaults to RANDOMIZATION_PERSISTENT and could be set
+     * to RANDOMIZATION_ENHANCED.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderSetMacRandomization() {
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .build();
+        assertEquals(WifiConfiguration.RANDOMIZATION_PERSISTENT,
+                suggestion.wifiConfiguration.macRandomizationSetting);
+
+        suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setIsEnhancedMacRandomizationEnabled(false)
+                .build();
+        assertEquals(WifiConfiguration.RANDOMIZATION_PERSISTENT,
+                suggestion.wifiConfiguration.macRandomizationSetting);
+
+        suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setIsEnhancedMacRandomizationEnabled(true)
+                .build();
+        assertEquals(WifiConfiguration.RANDOMIZATION_ENHANCED,
+                suggestion.wifiConfiguration.macRandomizationSetting);
+    }
+
+    /**
+     * Verify that the builder creates the appropriate PasspointConfiguration according to the
+     * enhanced MAC randomization setting.
+     */
+    @Test
+    public void testWifiNetworkSuggestionBuilderSetMacRandomizationPasspoint() {
+        PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setPasspointConfig(passpointConfiguration)
+                .build();
+        assertEquals(false, suggestion.passpointConfiguration.isEnhancedMacRandomizationEnabled());
+
+        suggestion = new WifiNetworkSuggestion.Builder()
+                .setPasspointConfig(passpointConfiguration)
+                .setIsEnhancedMacRandomizationEnabled(false)
+                .build();
+        assertEquals(false, suggestion.passpointConfiguration.isEnhancedMacRandomizationEnabled());
+
+        suggestion = new WifiNetworkSuggestion.Builder()
+                .setPasspointConfig(passpointConfiguration)
+                .setIsEnhancedMacRandomizationEnabled(true)
+                .build();
+        assertEquals(true, suggestion.passpointConfiguration.isEnhancedMacRandomizationEnabled());
+    }
+
+    /**
+     * Verify that the builder creates the appropriate SIM credential suggestion with SubId, also
+     * verify {@link WifiNetworkSuggestion#equals(Object)} consider suggestion with different SubId
+     * as different suggestions.
+     */
+    @Test
+    public void testSimCredentialNetworkWithSubId() {
+        assumeTrue(SdkLevel.isAtLeastS());
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+        WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa2EnterpriseConfig(enterpriseConfig)
+                .setSubscriptionId(1)
+                .build();
+        assertEquals(1, suggestion1.getSubscriptionId());
+        WifiNetworkSuggestion suggestion2 = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa2EnterpriseConfig(enterpriseConfig)
+                .setSubscriptionId(2)
+                .build();
+        assertEquals(2, suggestion2.getSubscriptionId());
+        assertNotEquals(suggestion1, suggestion2);
+    }
+
+    /**
      * Check that parcel marshalling/unmarshalling works
      */
     @Test
@@ -673,7 +1011,7 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
-                configuration, null, false, true, true, true);
+                configuration, null, false, true, true, true, TEST_PRIORITY_GROUP);
 
         Parcel parcelW = Parcel.obtain();
         suggestion.writeToParcel(parcelW, 0);
@@ -744,14 +1082,16 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, true, false, true, true);
+                new WifiNetworkSuggestion(configuration, null, true, false, true, true,
+                        TEST_PRIORITY_GROUP);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.BSSID = TEST_BSSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, true, true, true);
+                new WifiNetworkSuggestion(configuration1, null, false, true, true, true,
+                        DEFAULT_PRIORITY_GROUP);
 
         assertEquals(suggestion, suggestion1);
         assertEquals(suggestion.hashCode(), suggestion1.hashCode());
@@ -767,13 +1107,15 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+                new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+                        DEFAULT_PRIORITY_GROUP);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID_1;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+                        DEFAULT_PRIORITY_GROUP);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -789,13 +1131,15 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null,  false, false, true, true);
+                new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+                        DEFAULT_PRIORITY_GROUP);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+                        DEFAULT_PRIORITY_GROUP);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -810,13 +1154,15 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, false, false, true, true);
+                new WifiNetworkSuggestion(configuration, null, false, false, true, true,
+                        DEFAULT_PRIORITY_GROUP);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true, true,
+                        DEFAULT_PRIORITY_GROUP);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -932,6 +1278,78 @@
     }
 
     /**
+     * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the
+     * correct value to the WifiConfiguration.
+     */
+    @Test
+    public void testSetIsNetworkAsOemPaid() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa2Passphrase(TEST_PRESHARED_KEY)
+                .setOemPaid(true)
+                .build();
+        assertTrue(suggestion.isOemPaid());
+        assertFalse(suggestion.isUserAllowedToManuallyConnect);
+    }
+
+    /**
+     * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the
+     * correct value to the WifiConfiguration.
+     * Also the {@link WifiNetworkSuggestion#isUserAllowedToManuallyConnect} should be false;
+     */
+    @Test
+    public void testSetIsNetworkAsOemPaidOnPasspointNetwork() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setPasspointConfig(passpointConfiguration)
+                .setOemPaid(true)
+                .build();
+        assertTrue(suggestion.isOemPaid());
+        assertFalse(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.getPasspointConfig().isOemPaid());
+    }
+
+    /**
+     * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the
+     * correct value to the WifiConfiguration.
+     */
+    @Test
+    public void testSetIsNetworkAsOemPrivate() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa2Passphrase(TEST_PRESHARED_KEY)
+                .setOemPrivate(true)
+                .build();
+        assertTrue(suggestion.isOemPrivate());
+        assertFalse(suggestion.isUserAllowedToManuallyConnect);
+    }
+
+    /**
+     * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the
+     * correct value to the WifiConfiguration.
+     * Also the {@link WifiNetworkSuggestion#isUserAllowedToManuallyConnect} should be false;
+     */
+    @Test
+    public void testSetIsNetworkAsOemPrivateOnPasspointNetwork() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setPasspointConfig(passpointConfiguration)
+                .setOemPrivate(true)
+                .build();
+        assertTrue(suggestion.isOemPrivate());
+        assertFalse(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.getPasspointConfig().isOemPrivate());
+    }
+
+    /**
      * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
      * when set {@link WifiNetworkSuggestion.Builder#setUntrusted(boolean)} to true and
      * set {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to true
@@ -949,6 +1367,42 @@
 
     /**
      * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+     * when set {@link WifiNetworkSuggestion.Builder#setOemPaid(boolean)} to true and
+     * set {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to true
+     * together.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testSetCredentialSharedWithUserWithSetIsNetworkAsOemPaid() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa2Passphrase(TEST_PRESHARED_KEY)
+                .setCredentialSharedWithUser(true)
+                .setOemPaid(true)
+                .build();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+     * when set {@link WifiNetworkSuggestion.Builder#setOemPrivate(boolean)} to true and
+     * set {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to true
+     * together.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testSetCredentialSharedWithUserWithSetIsNetworkAsOemPrivate() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa2Passphrase(TEST_PRESHARED_KEY)
+                .setCredentialSharedWithUser(true)
+                .setOemPrivate(true)
+                .build();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
      * when set both {@link WifiNetworkSuggestion.Builder#setIsInitialAutojoinEnabled(boolean)}
      * and {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} (boolean)}
      * to false on a passpoint suggestion.
@@ -962,4 +1416,109 @@
                 .setIsInitialAutojoinEnabled(false)
                 .build();
     }
+
+    /**
+     * Validate {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)} set the
+     * correct value to the WifiConfiguration.
+     */
+    @Test
+    public void testSetCarrierMergedNetwork() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setSubscriptionId(1)
+                .setWpa2EnterpriseConfig(enterpriseConfig)
+                .setCarrierMerged(true)
+                .setIsMetered(true)
+                .build();
+        assertTrue(suggestion.isCarrierMerged());
+        assertTrue(suggestion.wifiConfiguration.carrierMerged);
+    }
+
+    /**
+     * Validate {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)} set the
+     * correct value to the passpoint network.
+     */
+    @Test
+    public void testSetCarrierMergedNetworkOnPasspointNetwork() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setPasspointConfig(passpointConfiguration)
+                .setSubscriptionId(1)
+                .setCarrierMerged(true)
+                .setIsMetered(true)
+                .build();
+        assertTrue(suggestion.isCarrierMerged());
+        assertTrue(suggestion.getPasspointConfig().isCarrierMerged());
+    }
+
+    /**
+     * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+     * when set both {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)}
+     * to true on a network is not metered.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testSetCarrierMergedNetworkOnUnmeteredNetworkFail() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+        new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setSubscriptionId(1)
+                .setWpa2EnterpriseConfig(enterpriseConfig)
+                .setCarrierMerged(true)
+                .build();
+    }
+
+    /**
+     * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+     * when set both {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)}
+     * to true on a network which {@link WifiNetworkSuggestion.Builder#setSubscriptionId(int)}
+     * is not set with a valid sub id.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testSetCarrierMergedNetworkWithoutValidSubscriptionIdFail() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+        enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setWpa2EnterpriseConfig(enterpriseConfig)
+                .setCarrierMerged(true)
+                .setIsMetered(true)
+                .build();
+        assertTrue(suggestion.isCarrierMerged());
+    }
+
+    /**
+     * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+     * when set both {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)}
+     * to true on a non enterprise network.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testSetCarrierMergedNetworkWithNonEnterpriseNetworkFail() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setSubscriptionId(1)
+                .setWpa2Passphrase(TEST_PRESHARED_KEY)
+                .setCarrierMerged(true)
+                .setIsMetered(true)
+                .build();
+        assertTrue(suggestion.isCarrierMerged());
+    }
 }
diff --git a/framework/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/framework/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 43d728b..1ecd325 100644
--- a/framework/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/framework/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -16,11 +16,13 @@
 
 package android.net.wifi.aware;
 
+import static android.net.wifi.aware.WifiAwareManager.WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE;
 import static android.net.wifi.aware.WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB;
 
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -45,6 +47,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -146,6 +150,39 @@
         verify(mockAwareService).getCharacteristics();
     }
 
+    /**
+     * Validate pass-through of isDeviceAttached() API.
+     */
+    @Test
+    public void testIsAttached() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        mDut.isDeviceAttached();
+        verify(mockAwareService).isDeviceAttached();
+    }
+
+    /**
+     * Validate pass-through of isInstantCommunicationModeEnabled() and
+     * enableInstantCommunicationMode() API
+     */
+    @Test
+    public void testEnableInstantCommunicationMode() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        mDut.isInstantCommunicationModeEnabled();
+        verify(mockAwareService).isInstantCommunicationModeEnabled();
+        mDut.enableInstantCommunicationMode(true);
+        verify(mockAwareService).enableInstantCommunicationMode(anyString(), eq(true));
+    }
+
+    /**
+     * Validate pass-through of getAvailableAwareResources() API.
+     */
+    @Test
+    public void testGetAvailableAwareResource() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        mDut.getAvailableAwareResources();
+        verify(mockAwareService).getAvailableAwareResources();
+    }
+
     /*
      * WifiAwareEventCallbackProxy Tests
      */
@@ -360,12 +397,19 @@
                 eq(publishConfig));
         inOrder.verify(mockSessionCallback).onSessionConfigFailed();
 
-        // (5) terminate
+        // (5) discovery session is no longer visible
+        sessionProxyCallback.getValue().onMatchExpired(peerHandle.peerId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onServiceLost(peerIdCaptor.capture(),
+                eq(WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE));
+        assertEquals(peerHandle.peerId, peerIdCaptor.getValue().peerId);
+
+        // (6) terminate
         publishSession.getValue().close();
         mMockLooper.dispatchAll();
         inOrder.verify(mockAwareService).terminateSession(clientId, sessionId);
 
-        // (6) try an update (nothing)
+        // (7) try an update (nothing)
         publishSession.getValue().updatePublish(publishConfig);
         mMockLooper.dispatchAll();
 
@@ -502,12 +546,19 @@
                 eq(subscribeConfig));
         inOrder.verify(mockSessionCallback).onSessionConfigFailed();
 
-        // (5) terminate
+        // (5) discovery session is no longer visible
+        sessionProxyCallback.getValue().onMatchExpired(peerHandle.peerId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockSessionCallback).onServiceLost(peerIdCaptor.capture(),
+                eq(WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE));
+        assertEquals(peerHandle.peerId, peerIdCaptor.getValue().peerId);
+
+        // (6) terminate
         subscribeSession.getValue().close();
         mMockLooper.dispatchAll();
         inOrder.verify(mockAwareService).terminateSession(clientId, sessionId);
 
-        // (6) try an update (nothing)
+        // (7) try an update (nothing)
         subscribeSession.getValue().updateSubscribe(subscribeConfig);
         mMockLooper.dispatchAll();
 
diff --git a/framework/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/framework/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 8270d64..badcf52 100644
--- a/framework/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/framework/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -186,6 +186,7 @@
         assertFalse(config.validateForR2());
         assertTrue(config.isAutojoinEnabled());
         assertTrue(config.isMacRandomizationEnabled());
+        assertFalse(config.isEnhancedMacRandomizationEnabled());
         assertTrue(config.getMeteredOverride() == METERED_OVERRIDE_NONE);
     }
 
diff --git a/framework/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java b/framework/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
index 8d55acb..5830a1e 100644
--- a/framework/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
+++ b/framework/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
@@ -30,6 +30,7 @@
 
 public class PasspointTestUtils {
     private static final int CERTIFICATE_FINGERPRINT_BYTES = 32;
+    private static final int TEST_SUB_ID = 1;
 
     /**
      * Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
@@ -156,6 +157,7 @@
         friendlyNames.put("en", "ServiceName1");
         friendlyNames.put("kr", "ServiceName2");
         config.setServiceFriendlyNames(friendlyNames);
+        config.setSubscriptionId(TEST_SUB_ID);
         return config;
     }
 
diff --git a/framework/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java b/framework/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
index 93d471a..fe889fc 100644
--- a/framework/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
+++ b/framework/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.hotspot2.pps;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
@@ -26,7 +27,9 @@
 import org.junit.Test;
 
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -35,6 +38,7 @@
  */
 @SmallTest
 public class HomeSpTest {
+    private static final String[] OTHER_HOME_PARTNER_LIST = new String[]{"partner1", "partner2"};
 
     /**
      * Helper function for creating a map of home network IDs for testing.
@@ -62,7 +66,7 @@
         homeSp.setHomeNetworkIds(homeNetworkIds);
         homeSp.setMatchAllOis(new long[] {0x11L, 0x22L});
         homeSp.setMatchAnyOis(new long[] {0x33L, 0x44L});
-        homeSp.setOtherHomePartners(new String[] {"partner1", "partner2"});
+        homeSp.setOtherHomePartners(OTHER_HOME_PARTNER_LIST);
         homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
         return homeSp;
     }
@@ -218,4 +222,34 @@
         HomeSp copySp = new HomeSp(sourceSp);
         assertTrue(copySp.equals(sourceSp));
     }
+
+    /**
+     * Verify that the getOtherHomePartnersList gets the list of partners as expected.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateGetOtherHomePartnersList() throws Exception {
+        HomeSp homeSp = createHomeSpWithoutHomeNetworkIds();
+
+        Collection<String> otherHomePartnersList = homeSp.getOtherHomePartnersList();
+        assertEquals(2, otherHomePartnersList.size());
+        assertTrue(Arrays.equals(OTHER_HOME_PARTNER_LIST, otherHomePartnersList.toArray()));
+    }
+
+    /**
+     * Verify that the setOtherHomePartnersList sets the list of partners as expected.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateSetOtherHomePartnersList() throws Exception {
+        HomeSp homeSp = createHomeSpWithoutHomeNetworkIds();
+
+        final Collection<String> homePartners =
+                new ArrayList<>(Arrays.asList(OTHER_HOME_PARTNER_LIST));
+
+        homeSp.setOtherHomePartnersList(homePartners);
+        assertTrue(Arrays.equals(homeSp.getOtherHomePartners(), OTHER_HOME_PARTNER_LIST));
+    }
 }
diff --git a/framework/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/framework/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index e6eae41..c8006fe 100644
--- a/framework/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/framework/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -16,6 +16,8 @@
 
 package android.net.wifi.rtt;
 
+import static junit.framework.Assert.fail;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -143,6 +145,7 @@
         PeerHandle peerHandle1 = new PeerHandle(12);
 
         RangingRequest.Builder builder = new RangingRequest.Builder();
+        builder.setRttBurstSize(4);
         builder.addAccessPoint(scanResult1);
         builder.addAccessPoints(scanResults2and3);
         builder.addWifiAwarePeer(mac1);
@@ -163,6 +166,60 @@
     }
 
     /**
+     * Validate the rtt burst size is set correctly when in range.
+     */
+    @Test
+    public void testRangingRequestSetBurstSize() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.BSSID = "AA:BB:CC:DD:EE:FF";
+
+        // create request
+        RangingRequest.Builder builder = new RangingRequest.Builder();
+        builder.setRttBurstSize(4);
+        builder.addAccessPoint(scanResult);
+        RangingRequest request = builder.build();
+
+        // confirm rtt burst size is set correctly to default value
+        assertEquals(request.getRttBurstSize(), 4);
+    }
+
+    /**
+     * Validate the rtt burst size cannot be smaller than the minimum.
+     */
+    @Test
+    public void testRangingRequestMinBurstSizeIsEnforced() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.BSSID = "AA:BB:CC:DD:EE:FF";
+
+        // create request
+        try {
+            RangingRequest.Builder builder = new RangingRequest.Builder();
+            builder.setRttBurstSize(RangingRequest.getMinRttBurstSize() - 1);
+            fail("RTT burst size was smaller than min value.");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Validate the rtt burst size cannot exceed the maximum.
+     */
+    @Test
+    public void testRangingRequestMaxBurstSizeIsEnforced() {
+        ScanResult scanResult = new ScanResult();
+        scanResult.BSSID = "AA:BB:CC:DD:EE:FF";
+
+        // create request
+        try {
+            RangingRequest.Builder builder = new RangingRequest.Builder();
+            builder.setRttBurstSize(RangingRequest.getMaxRttBurstSize() + 1);
+            fail("RTT Burst size exceeded max value.");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    /**
      * Validate that can request as many range operation as the upper limit on number of requests.
      */
     @Test
@@ -175,7 +232,7 @@
         }
         MacAddress mac1 = MacAddress.fromString("00:01:02:03:04:05");
 
-        // create request
+        // create request using max RTT Peers
         RangingRequest.Builder builder = new RangingRequest.Builder();
         builder.addAccessPoint(scanResult);
         builder.addAccessPoints(scanResultList);
@@ -185,6 +242,18 @@
 
         // verify request
         request.enforceValidity(true);
+        // confirm rtt burst size is set correctly to default value
+        assertEquals(request.getRttBurstSize(), RangingRequest.getDefaultRttBurstSize());
+        // confirm the number of peers in the request is the max number of peers
+        List<ResponderConfig> rttPeers = request.getRttPeers();
+        int numRttPeers = rttPeers.size();
+        assertEquals(RangingRequest.getMaxPeers(), numRttPeers);
+        // confirm each peer has the correct mac address
+        for (int i = 0; i < numRttPeers - 1; ++i) {
+            assertEquals("AA:BB:CC:DD:EE:FF", rttPeers.get(i).macAddress.toString().toUpperCase());
+        }
+        assertEquals("00:01:02:03:04:05",
+                rttPeers.get(numRttPeers - 1).macAddress.toString().toUpperCase());
     }
 
     /**