Merge "Bulk apply PendingIntent.FLAG_MUTABLE_UNAUDITED."
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index 3ebe9b1..768929b 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -1033,11 +1033,27 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="    <color name="homepage_wallpaper_background">#E51AD1</color>"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/values/colors.xml"
+            line="102"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
         errorLine1="    &lt;color name=&quot;contextual_card_stroke_color&quot;>#1f000000&lt;/color>"
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="103"
+            line="104"
             column="5"/>
     </issue>
 
@@ -1053,7 +1069,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="109"
+            line="110"
             column="5"/>
     </issue>
 
@@ -1069,7 +1085,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="112"
+            line="113"
             column="5"/>
     </issue>
 
@@ -1085,7 +1101,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="113"
+            line="114"
             column="5"/>
     </issue>
 
@@ -1101,7 +1117,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="114"
+            line="115"
             column="5"/>
     </issue>
 
@@ -1117,7 +1133,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="115"
+            line="116"
             column="5"/>
     </issue>
 
@@ -1133,7 +1149,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="116"
+            line="117"
             column="5"/>
     </issue>
 
@@ -1149,7 +1165,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="117"
+            line="118"
             column="5"/>
     </issue>
 
@@ -1165,7 +1181,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="120"
+            line="121"
             column="5"/>
     </issue>
 
@@ -1181,7 +1197,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="121"
+            line="122"
             column="5"/>
     </issue>
 
@@ -1197,7 +1213,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="122"
+            line="123"
             column="5"/>
     </issue>
 
@@ -1213,7 +1229,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="123"
+            line="124"
             column="5"/>
     </issue>
 
@@ -1229,7 +1245,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="124"
+            line="125"
             column="5"/>
     </issue>
 
@@ -1245,7 +1261,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="127"
+            line="128"
             column="5"/>
     </issue>
 
@@ -1261,7 +1277,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="128"
+            line="129"
             column="5"/>
     </issue>
 
@@ -1277,7 +1293,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="129"
+            line="130"
             column="5"/>
     </issue>
 
@@ -1293,7 +1309,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="130"
+            line="131"
             column="5"/>
     </issue>
 
@@ -1309,7 +1325,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="131"
+            line="132"
             column="5"/>
     </issue>
 
@@ -1325,7 +1341,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="132"
+            line="133"
             column="5"/>
     </issue>
 
@@ -1341,7 +1357,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="139"
+            line="140"
             column="5"/>
     </issue>
 
@@ -1357,7 +1373,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="140"
+            line="141"
             column="5"/>
     </issue>
 
@@ -1373,7 +1389,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="141"
+            line="142"
             column="5"/>
     </issue>
 
@@ -1389,7 +1405,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="150"
+            line="151"
             column="5"/>
     </issue>
 
@@ -1405,7 +1421,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="152"
+            line="153"
             column="5"/>
     </issue>
 
@@ -1421,7 +1437,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="156"
+            line="157"
             column="5"/>
     </issue>
 
@@ -1437,7 +1453,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="157"
+            line="158"
             column="5"/>
     </issue>
 
@@ -1453,7 +1469,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="158"
+            line="159"
             column="5"/>
     </issue>
 
@@ -1469,7 +1485,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="159"
+            line="160"
             column="5"/>
     </issue>
 
@@ -1485,7 +1501,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="160"
+            line="161"
             column="5"/>
     </issue>
 
@@ -1501,7 +1517,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="161"
+            line="162"
             column="5"/>
     </issue>
 
@@ -1517,7 +1533,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="162"
+            line="163"
             column="5"/>
     </issue>
 
@@ -1533,7 +1549,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="163"
+            line="164"
             column="5"/>
     </issue>
 
@@ -1549,7 +1565,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="166"
+            line="167"
             column="5"/>
     </issue>
 
@@ -1565,7 +1581,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="167"
+            line="168"
             column="5"/>
     </issue>
 
@@ -1581,7 +1597,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="168"
+            line="169"
             column="5"/>
     </issue>
 
@@ -1597,7 +1613,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="169"
+            line="170"
             column="5"/>
     </issue>
 
@@ -1613,7 +1629,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="170"
+            line="171"
             column="5"/>
     </issue>
 
@@ -1629,7 +1645,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="171"
+            line="172"
             column="5"/>
     </issue>
 
@@ -1645,7 +1661,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="172"
+            line="173"
             column="5"/>
     </issue>
 
@@ -1661,7 +1677,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="173"
+            line="174"
             column="5"/>
     </issue>
 
@@ -1677,7 +1693,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="176"
+            line="177"
             column="5"/>
     </issue>
 
@@ -1693,7 +1709,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="177"
+            line="178"
             column="5"/>
     </issue>
 
@@ -1709,7 +1725,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="178"
+            line="179"
             column="5"/>
     </issue>
 
@@ -1725,7 +1741,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="179"
+            line="180"
             column="5"/>
     </issue>
 
@@ -1741,7 +1757,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="180"
+            line="181"
             column="5"/>
     </issue>
 
@@ -1757,7 +1773,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="181"
+            line="182"
             column="5"/>
     </issue>
 
@@ -1773,7 +1789,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="184"
+            line="185"
             column="5"/>
     </issue>
 
@@ -1789,7 +1805,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="185"
+            line="186"
             column="5"/>
     </issue>
 
@@ -1805,7 +1821,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="186"
+            line="187"
             column="5"/>
     </issue>
 
@@ -1821,7 +1837,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="187"
+            line="188"
             column="5"/>
     </issue>
 
@@ -1837,7 +1853,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="188"
+            line="189"
             column="5"/>
     </issue>
 
@@ -1853,7 +1869,7 @@
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/colors.xml"
-            line="189"
+            line="190"
             column="5"/>
     </issue>
 
@@ -2569,6 +2585,22 @@
         priority="4"
         summary="Using hardcoded color"
         explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+        errorLine1="            android:color=&quot;@color/homepage_wallpaper_background&quot; />"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="res/drawable/ic_homepage_wallpaper.xml"
+            line="24"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="HardCodedColor"
+        severity="Error"
+        message="Avoid using hardcoded color"
+        category="Correctness"
+        priority="4"
+        summary="Using hardcoded color"
+        explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
         errorLine1="                    android:color=&quot;@color/notification_block_color&quot;/>"
         errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -3181,7 +3213,7 @@
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~">
         <location
             file="res/values/strings.xml"
-            line="6537"
+            line="6533"
             column="36"/>
     </issue>
 
diff --git a/res/drawable/ic_homepage_wallpaper.xml b/res/drawable/ic_homepage_wallpaper.xml
new file mode 100644
index 0000000..0f91465
--- /dev/null
+++ b/res/drawable/ic_homepage_wallpaper.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item>
+        <com.android.settingslib.widget.AdaptiveIconShapeDrawable
+            android:width="@dimen/dashboard_tile_image_size"
+            android:height="@dimen/dashboard_tile_image_size"
+            android:color="@color/homepage_wallpaper_background" />
+    </item>
+
+    <item
+        android:width="@dimen/dashboard_tile_foreground_image_size"
+        android:height="@dimen/dashboard_tile_foreground_image_size"
+        android:start="@dimen/dashboard_tile_foreground_image_inset"
+        android:top="@dimen/dashboard_tile_foreground_image_inset"
+        android:drawable="@drawable/ic_settings_wallpaper_white" />
+</layer-list>
diff --git a/res/drawable/ic_settings_wallpaper_white.xml b/res/drawable/ic_settings_wallpaper_white.xml
new file mode 100644
index 0000000..8591fb5
--- /dev/null
+++ b/res/drawable/ic_settings_wallpaper_white.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright (C) 2021 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="?android:attr/colorPrimary"
+        android:fillType="evenOdd"
+        android:pathData="M11,5H5V11H3V5C3,3.9 3.9,3 5,3H11V5ZM11.14,15.29L9,12.71L6,16.57H18L14.14,11.42L11.14,15.29ZM19,13V19H13V21H19C20.1,21 21,20.1 21,19V13H19ZM5,13V19H11V21H5C3.9,21 3,20.1 3,19V13H5ZM19,5V11H21V5C21,3.9 20.1,3 19,3H13V5H19ZM17,8C17,8.55 16.55,9 16,9C15.45,9 15,8.55 15,8C15,7.45 15.45,7 16,7C16.55,7 17,7.45 17,8Z"/>
+</vector>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 3528f9f..183dd1e 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -223,6 +223,10 @@
     <!-- Security types for wireless tether -->
     <string-array name="wifi_tether_security">
         <!-- Do not translate. -->
+        <item>@string/wifi_security_sae</item>
+        <!-- Do not translate. -->
+        <item>@string/wifi_security_psk_sae</item>
+        <!-- Do not translate. -->
         <item>@string/wifi_security_wpa2</item>
         <!-- Do not translate. -->
         <item>@string/wifi_security_none</item>
@@ -231,6 +235,10 @@
     <!-- Values for security type for wireless tether -->
     <string-array name="wifi_tether_security_values" translatable="false">
         <!-- Do not translate. -->
+        <item>3</item>
+        <!-- Do not translate. -->
+        <item>2</item>
+        <!-- Do not translate. -->
         <item>1</item>
         <!-- Do not translate. -->
         <item>0</item>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 2ce3949..c858cb3 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -99,6 +99,7 @@
     <color name="homepage_location_background">#2EC7DC</color>
     <color name="homepage_about_background">#6F86DA</color>
     <color name="homepage_privacy_background">#5E97F6</color>
+    <color name="homepage_wallpaper_background">#E51AD1</color>
 
     <color name="contextual_card_stroke_color">#1f000000</color>
     <color name="contextual_card_dismissal_background">@*android:color/material_grey_100</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f52c818..d687357 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8584,7 +8584,7 @@
     <!-- [CHAR LIMIT=100] preference category title -->
     <string name="recent_conversations">Recent conversations</string>
 
-    <!-- [CHAR LIMIT=20] button title -->
+    <!-- [CHAR LIMIT=40] button title -->
     <string name="conversation_settings_clear_recents">Clear all of the recent ones</string>
 
     <!-- a11y string -->
diff --git a/res/xml/emergency_settings.xml b/res/xml/emergency_settings.xml
index 41b503e..31c209b 100644
--- a/res/xml/emergency_settings.xml
+++ b/res/xml/emergency_settings.xml
@@ -23,15 +23,18 @@
         android:key="emergency_info"
         android:title="@string/emergency_info_title"
         android:summary="@string/summary_placeholder"
+        android:order="0"
         settings:controller="com.android.settings.accounts.EmergencyInfoPreferenceController"/>
     <Preference
         android:key="gesture_emergency_summary"
         android:title="@string/emergency_gesture_screen_title"
+        android:order="100"
         android:fragment="com.android.settings.gestures.EmergencyGestureSettings"
         settings:controller="com.android.settings.gestures.EmergencyGestureEntrypointPreferenceController" />
     <com.android.settingslib.RestrictedPreference
         android:key="app_and_notif_cell_broadcast_settings"
         android:title="@string/cell_broadcast_settings"
+        android:order="200"
         settings:useAdminDisabledSummary="true">
         <intent
             android:action="android.intent.action.MAIN"
diff --git a/res/xml/top_level_settings_grouped.xml b/res/xml/top_level_settings_grouped.xml
index 1ae6131..3fe52bb 100644
--- a/res/xml/top_level_settings_grouped.xml
+++ b/res/xml/top_level_settings_grouped.xml
@@ -93,7 +93,7 @@
             settings:controller="com.android.settings.display.TopLevelDisplayPreferenceController"/>
 
         <com.android.settingslib.RestrictedTopLevelPreference
-            android:icon="@drawable/ic_homepage_display"
+            android:icon="@drawable/ic_homepage_wallpaper"
             android:key="top_level_wallpaper"
             android:order="-60"
             android:title="@string/wallpaper_settings_title"
diff --git a/src/com/android/settings/AllInOneTetherSettings.java b/src/com/android/settings/AllInOneTetherSettings.java
index 82e3206..5442ed7 100644
--- a/src/com/android/settings/AllInOneTetherSettings.java
+++ b/src/com/android/settings/AllInOneTetherSettings.java
@@ -355,7 +355,7 @@
     @Override
     public void onTetherConfigUpdated(AbstractPreferenceController controller) {
         final SoftApConfiguration config = buildNewConfig();
-        mPasswordPreferenceController.updateVisibility(config.getSecurityType());
+        mPasswordPreferenceController.setSecurityType(config.getSecurityType());
         mWifiManager.setSoftApConfiguration(config);
 
         if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
diff --git a/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarController.java b/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarController.java
index 31ce9d8..1a58b39 100644
--- a/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarController.java
+++ b/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarController.java
@@ -30,6 +30,7 @@
 import android.widget.SeekBar;
 import android.widget.TextView;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
@@ -49,7 +50,9 @@
 
     private static final String CONTROL_AUTOCLICK_DELAY_SECURE =
             Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY;
-    private static final String KEY_CUSTOM_DELAY_VALUE = "custom_delay_value";
+
+    @VisibleForTesting
+    static final String KEY_CUSTOM_DELAY_VALUE = "custom_delay_value";
 
     // Min allowed autoclick delay value.
     static final int MIN_AUTOCLICK_DELAY_MS = 200;
@@ -59,7 +62,8 @@
 
     // Allowed autoclick delay values are discrete.
     // This is the difference between two allowed values.
-    private static final int AUTOCLICK_DELAY_STEP = 100;
+    @VisibleForTesting
+    static final int AUTOCLICK_DELAY_STEP = 100;
 
     private final SharedPreferences mSharedPreferences;
     private final ContentResolver mContentResolver;
@@ -68,7 +72,8 @@
     private SeekBar mSeekBar;
     private TextView mDelayLabel;
 
-    private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
+    @VisibleForTesting
+    final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
             new SeekBar.OnSeekBarChangeListener() {
 
                 @Override
diff --git a/src/com/android/settings/emergency/EmergencyDashboardFragment.java b/src/com/android/settings/emergency/EmergencyDashboardFragment.java
index c786767..1983430 100644
--- a/src/com/android/settings/emergency/EmergencyDashboardFragment.java
+++ b/src/com/android/settings/emergency/EmergencyDashboardFragment.java
@@ -44,7 +44,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return SettingsEnums.EMERGENCY_SOS_GESTURE_SETTINGS;
+        return SettingsEnums.EMERGENCY_SETTINGS;
     }
 
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
diff --git a/src/com/android/settings/media/BluetoothPairingReceiver.java b/src/com/android/settings/media/BluetoothPairingReceiver.java
index 5b57800..1ec99b0 100644
--- a/src/com/android/settings/media/BluetoothPairingReceiver.java
+++ b/src/com/android/settings/media/BluetoothPairingReceiver.java
@@ -25,7 +25,7 @@
 import com.android.settings.R;
 import com.android.settings.bluetooth.BluetoothPairingDetail;
 import com.android.settings.core.SubSettingLauncher;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 
 /**
  * BroadcastReceiver for handling media output intent
@@ -33,7 +33,7 @@
 public class BluetoothPairingReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
-        if (TextUtils.equals(MediaOutputSliceConstants.ACTION_LAUNCH_BLUETOOTH_PAIRING,
+        if (TextUtils.equals(MediaOutputConstants.ACTION_LAUNCH_BLUETOOTH_PAIRING,
                 intent.getAction())) {
             context.startActivity(new SubSettingLauncher(context)
                     .setDestination(BluetoothPairingDetail.class.getName())
diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
index 69e5dde..10a8b79 100644
--- a/src/com/android/settings/media/MediaOutputIndicatorSlice.java
+++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
@@ -36,7 +36,7 @@
 import com.android.settings.Utils;
 import com.android.settings.slices.CustomSliceable;
 import com.android.settings.slices.SliceBackgroundWorker;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 
 public class MediaOutputIndicatorSlice implements CustomSliceable {
 
@@ -128,15 +128,15 @@
         }
         // Launch media output dialog
         mContext.sendBroadcast(new Intent()
-                .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)
-                .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
-                .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN,
+                .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME)
+                .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
+                .putExtra(MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN,
                         mediaController.getSessionToken())
-                .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+                .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME,
                         mediaController.getPackageName()));
         // Dismiss volume panel
         mContext.sendBroadcast(new Intent()
-                .setPackage(MediaOutputSliceConstants.SETTINGS_PACKAGE_NAME)
-                .setAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL));
+                .setPackage(MediaOutputConstants.SETTINGS_PACKAGE_NAME)
+                .setAction(MediaOutputConstants.ACTION_CLOSE_PANEL));
     }
 }
diff --git a/src/com/android/settings/media/RemoteMediaSlice.java b/src/com/android/settings/media/RemoteMediaSlice.java
index 839dc4f..e69c005 100644
--- a/src/com/android/settings/media/RemoteMediaSlice.java
+++ b/src/com/android/settings/media/RemoteMediaSlice.java
@@ -48,7 +48,7 @@
 import com.android.settings.slices.SliceBackgroundWorker;
 import com.android.settings.slices.SliceBroadcastReceiver;
 import com.android.settings.slices.SliceBuilderUtils;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 
 import java.util.List;
 
@@ -86,14 +86,14 @@
             // Launch Media Output Dialog
             final RoutingSessionInfo info = intent.getParcelableExtra(SESSION_INFO);
             mContext.sendBroadcast(new Intent()
-                    .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)
-                    .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
-                    .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+                    .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME)
+                    .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
+                    .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME,
                             info.getClientPackageName()));
             // Dismiss volume panel
             mContext.sendBroadcast(new Intent()
-                    .setPackage(MediaOutputSliceConstants.SETTINGS_PACKAGE_NAME)
-                    .setAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL));
+                    .setPackage(MediaOutputConstants.SETTINGS_PACKAGE_NAME)
+                    .setAction(MediaOutputConstants.ACTION_CLOSE_PANEL));
         }
     }
 
diff --git a/src/com/android/settings/notification/RemoteVolumeGroupController.java b/src/com/android/settings/notification/RemoteVolumeGroupController.java
index eaff9e1..dd6f516 100644
--- a/src/com/android/settings/notification/RemoteVolumeGroupController.java
+++ b/src/com/android/settings/notification/RemoteVolumeGroupController.java
@@ -34,7 +34,7 @@
 import com.android.settingslib.core.lifecycle.events.OnDestroy;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.ArrayList;
@@ -196,9 +196,9 @@
             if (TextUtils.equals(info.getId(),
                     preference.getKey().substring(SWITCHER_PREFIX.length()))) {
                 final Intent intent = new Intent()
-                        .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
-                        .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)
-                        .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+                        .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
+                        .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME)
+                        .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME,
                                 info.getClientPackageName());
                 mContext.sendBroadcast(intent);
                 return true;
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index b7b1519..856dc35 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.panel;
 
-import static com.android.settingslib.media.MediaOutputSliceConstants.EXTRA_PACKAGE_NAME;
+import static com.android.settingslib.media.MediaOutputConstants.EXTRA_PACKAGE_NAME;
 
 import android.content.Intent;
 import android.content.res.Configuration;
diff --git a/src/com/android/settings/panel/VolumePanel.java b/src/com/android/settings/panel/VolumePanel.java
index b5e807d..3e6d1ce 100644
--- a/src/com/android/settings/panel/VolumePanel.java
+++ b/src/com/android/settings/panel/VolumePanel.java
@@ -38,7 +38,7 @@
 import androidx.lifecycle.OnLifecycleEvent;
 
 import com.android.settings.R;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -55,7 +55,7 @@
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (MediaOutputSliceConstants.ACTION_CLOSE_PANEL.equals(intent.getAction())) {
+            if (MediaOutputConstants.ACTION_CLOSE_PANEL.equals(intent.getAction())) {
                 mCallback.forceClose();
             }
         }
@@ -73,7 +73,7 @@
     @OnLifecycleEvent(ON_RESUME)
     public void onResume() {
         final IntentFilter filter = new IntentFilter();
-        filter.addAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL);
+        filter.addAction(MediaOutputConstants.ACTION_CLOSE_PANEL);
         mContext.registerReceiver(mReceiver, filter);
     }
 
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index be71b30..e40b164 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -46,7 +46,7 @@
 import com.android.settings.wifi.calling.WifiCallingSliceHelper;
 import com.android.settings.wifi.slice.ContextualWifiSlice;
 import com.android.settings.wifi.slice.WifiSlice;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 
 import java.util.Map;
 
@@ -293,7 +293,7 @@
             .scheme(ContentResolver.SCHEME_CONTENT)
             .authority(SettingsSliceProvider.SLICE_AUTHORITY)
             .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
-            .appendPath(MediaOutputSliceConstants.KEY_REMOTE_MEDIA)
+            .appendPath(MediaOutputConstants.KEY_REMOTE_MEDIA)
             .build();
 
     /**
diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java
index b5562a3..4ec00e3 100644
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -32,7 +32,7 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 
 import java.util.List;
 
@@ -134,11 +134,11 @@
     public boolean handlePreferenceTreeClick(Preference preference) {
         if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
             mContext.sendBroadcast(new Intent()
-                    .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
-                    .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)
-                    .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+                    .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
+                    .setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME)
+                    .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME,
                             mMediaController.getPackageName())
-                    .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN,
+                    .putExtra(MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN,
                             mMediaController.getSessionToken()));
             return true;
         }
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
index 06f74d5..d05260a 100644
--- a/src/com/android/settings/wifi/WifiUtils.java
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -56,12 +56,12 @@
     }
 
     /**
-     * Check if the WPA2-PSK hotspot password is valid.
+     * Check if the hotspot password is valid.
      */
-    public static boolean isHotspotWpa2PasswordValid(String password) {
+    public static boolean isHotspotPasswordValid(String password, int securityType) {
         final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
         try {
-            configBuilder.setPassphrase(password, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+            configBuilder.setPassphrase(password, securityType);
         } catch (IllegalArgumentException e) {
             return false;
         }
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 2957e1f..abf5bec 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -301,7 +301,11 @@
 
         final String ssid = removeFirstAndLastDoubleQuotes(softApConfiguration.getSsid());
         String security;
-        if (softApConfiguration.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) {
+        final int securityType = softApConfiguration.getSecurityType();
+        if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE) {
+            security = WifiQrCode.SECURITY_SAE;
+        } else if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
+                || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION) {
             security = WifiQrCode.SECURITY_WPA_PSK;
         } else {
             security = WifiQrCode.SECURITY_NO_PASSWORD;
@@ -431,11 +435,11 @@
 
     private static boolean isSupportHotspotConfiguratorQrCodeGenerator(
             SoftApConfiguration softApConfiguration) {
-        // QR code generator produces QR code with ZXing's Wi-Fi network config format,
-        // it supports PSK and WEP and non security
-        // KeyMgmt.NONE is for WEP or non security
-        return softApConfiguration.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
-                || softApConfiguration.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_OPEN;
+        final int securityType = softApConfiguration.getSecurityType();
+        return securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE
+                || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION
+                || securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
+                || securityType == SoftApConfiguration.SECURITY_TYPE_OPEN;
     }
 
     private static boolean isSupportWifiDpp(Context context, int wifiEntrySecurity) {
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
index be67d22..14766f9 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
@@ -37,12 +37,16 @@
 
 import java.util.UUID;
 
+/**
+ * Controller for logic pertaining to the password of Wi-Fi tethering.
+ */
 public class WifiTetherPasswordPreferenceController extends WifiTetherBasePreferenceController
         implements ValidatedEditTextPreference.Validator {
 
     private static final String PREF_KEY = "wifi_tether_network_password";
 
     private String mPassword;
+    private int mSecurityType;
 
     private final MetricsFeatureProvider mMetricsFeatureProvider;
 
@@ -68,13 +72,13 @@
     @Override
     public void updateDisplay() {
         final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
-        if (config == null
-                || (config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
-                && TextUtils.isEmpty(config.getPassphrase()))) {
+        if (config.getSecurityType() != SoftApConfiguration.SECURITY_TYPE_OPEN
+                && TextUtils.isEmpty(config.getPassphrase())) {
             mPassword = generateRandomPassword();
         } else {
             mPassword = config.getPassphrase();
         }
+        mSecurityType = config.getSecurityType();
         ((ValidatedEditTextPreference) mPreference).setValidator(this);
         ((ValidatedEditTextPreference) mPreference).setIsPassword(true);
         ((ValidatedEditTextPreference) mPreference).setIsSummaryPassword(true);
@@ -105,20 +109,27 @@
         // don't actually overwrite unless we get a new config in case it was accidentally toggled.
         if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) {
             return "";
-        } else if (!isTextValid(mPassword)) {
+        } else if (!WifiUtils.isHotspotPasswordValid(mPassword, securityType)) {
             mPassword = generateRandomPassword();
             updatePasswordDisplay((EditTextPreference) mPreference);
         }
         return mPassword;
     }
 
-    public void updateVisibility(int securityType) {
+    /**
+     * This method set the security type of user selection. Then the controller will based on the
+     * security type changed to update the password changed on the preference.
+     *
+     * @param securityType The security type of SoftApConfiguration.
+     */
+    public void setSecurityType(int securityType) {
+        mSecurityType = securityType;
         mPreference.setVisible(securityType != SoftApConfiguration.SECURITY_TYPE_OPEN);
     }
 
     @Override
     public boolean isTextValid(String value) {
-        return WifiUtils.isHotspotWpa2PasswordValid(value);
+        return WifiUtils.isHotspotPasswordValid(value, mSecurityType);
     }
 
     private static String generateRandomPassword() {
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
index 56b5031..acb8206 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
@@ -1,28 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.settings.wifi.tether;
 
 import static com.android.settings.AllInOneTetherSettings.DEDUP_POSTFIX;
 
+import android.annotation.NonNull;
 import android.content.Context;
+import android.net.wifi.SoftApCapability;
 import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiManager;
 import android.util.FeatureFlagUtils;
+import android.util.Log;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
 import com.android.settings.core.FeatureFlags;
 
-public class WifiTetherSecurityPreferenceController extends WifiTetherBasePreferenceController {
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Controller for logic pertaining to the security type of Wi-Fi tethering.
+ */
+public class WifiTetherSecurityPreferenceController extends WifiTetherBasePreferenceController
+        implements WifiManager.SoftApCallback {
 
     private static final String PREF_KEY = "wifi_tether_security";
 
-    private final String[] mSecurityEntries;
+    private Map<Integer, String> mSecurityMap = new LinkedHashMap<Integer, String>();
     private int mSecurityValue;
+    @VisibleForTesting
+    boolean mIsWpa3Supported = true;
 
     public WifiTetherSecurityPreferenceController(Context context,
             OnTetherConfigUpdateListener listener) {
         super(context, listener);
-        mSecurityEntries = mContext.getResources().getStringArray(R.array.wifi_tether_security);
+        final String[] securityNames = mContext.getResources().getStringArray(
+                R.array.wifi_tether_security);
+        final String[] securityValues = mContext.getResources().getStringArray(
+                R.array.wifi_tether_security_values);
+        for (int i = 0; i < securityNames.length; i++) {
+            mSecurityMap.put(Integer.parseInt(securityValues[i]), securityNames[i]);
+        }
+        mWifiManager.registerSoftApCallback(context.getMainExecutor(), this);
     }
 
     @Override
@@ -33,35 +70,55 @@
 
     @Override
     public void updateDisplay() {
-        final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
-        if (config != null && config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_OPEN) {
-            mSecurityValue = SoftApConfiguration.SECURITY_TYPE_OPEN;
-        } else {
-            mSecurityValue = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+        // The mPreference will be ready when the fragment calls displayPreference(). Since the
+        // capability of WPA3 hotspot callback will update the preference list here, add null point
+        // checking to avoid the mPreference is not ready when the fragment is loading for settings
+        // keyword searching only.
+        if (mPreference == null) {
+            return;
+        }
+        final ListPreference preference = (ListPreference) mPreference;
+        // If the device is not support WPA3 then remove the WPA3 options.
+        if (!mIsWpa3Supported && mSecurityMap.keySet()
+                .removeIf(key -> key > SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)) {
+            preference.setEntries(mSecurityMap.values().stream().toArray(CharSequence[]::new));
+            preference.setEntryValues(mSecurityMap.keySet().stream().map(Integer::toBinaryString)
+                    .toArray(CharSequence[]::new));
         }
 
-        final ListPreference preference = (ListPreference) mPreference;
-        preference.setSummary(getSummaryForSecurityType(mSecurityValue));
+        final int securityType = mWifiManager.getSoftApConfiguration().getSecurityType();
+        mSecurityValue = mSecurityMap.get(securityType) != null
+                ? securityType : SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+
+        preference.setSummary(mSecurityMap.get(mSecurityValue));
         preference.setValue(String.valueOf(mSecurityValue));
     }
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         mSecurityValue = Integer.parseInt((String) newValue);
-        preference.setSummary(getSummaryForSecurityType(mSecurityValue));
-        mListener.onTetherConfigUpdated(this);
+        preference.setSummary(mSecurityMap.get(mSecurityValue));
+        if (mListener != null) {
+            mListener.onTetherConfigUpdated(this);
+        }
         return true;
     }
 
+    @Override
+    public void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
+        final boolean isWpa3Supported =
+                softApCapability.areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE);
+        if (!isWpa3Supported) {
+            Log.i(PREF_KEY, "WPA3 SAE is not supported on this device");
+        }
+        if (mIsWpa3Supported != isWpa3Supported) {
+            mIsWpa3Supported = isWpa3Supported;
+            updateDisplay();
+        }
+        mWifiManager.unregisterSoftApCallback(this);
+    }
+
     public int getSecurityType() {
         return mSecurityValue;
     }
-
-    private String getSummaryForSecurityType(int securityType) {
-        if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) {
-            return mSecurityEntries[1];
-        }
-        // WPA2 PSK
-        return mSecurityEntries[0];
-    }
 }
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index d6c49bc..f260298 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -192,7 +192,7 @@
     @Override
     public void onTetherConfigUpdated(AbstractPreferenceController context) {
         final SoftApConfiguration config = buildNewConfig();
-        mPasswordPreferenceController.updateVisibility(config.getSecurityType());
+        mPasswordPreferenceController.setSecurityType(config.getSecurityType());
 
         /**
          * if soft AP is stopped, bring up
@@ -216,10 +216,10 @@
         final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
         final int securityType = mSecurityPreferenceController.getSecurityType();
         configBuilder.setSsid(mSSIDPreferenceController.getSSID());
-        if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) {
+        if (securityType != SoftApConfiguration.SECURITY_TYPE_OPEN) {
             configBuilder.setPassphrase(
                     mPasswordPreferenceController.getPasswordValidated(securityType),
-                    SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+                    securityType);
         }
         configBuilder.setBand(mApBandPreferenceController.getBandIndex());
         return configBuilder.build();
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarControllerTest.java
new file mode 100644
index 0000000..d6c66ad
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickCustomSeekbarControllerTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.settings.accessibility.ToggleAutoclickCustomSeekbarController.KEY_CUSTOM_DELAY_VALUE;
+import static com.android.settings.accessibility.ToggleAutoclickPreferenceController.KEY_DELAY_MODE;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import androidx.lifecycle.LifecycleObserver;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.widget.LayoutPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link ToggleAutoclickCustomSeekbarController}. */
+@RunWith(RobolectricTestRunner.class)
+public class ToggleAutoclickCustomSeekbarControllerTest {
+
+    @Mock
+    private PreferenceScreen mScreen;
+
+    @Mock
+    private LayoutPreference mLayoutPreference;
+
+    @Mock
+    private Lifecycle mLifecycle;
+
+    private SharedPreferences mSharedPreferences;
+    private TextView mDelayLabel;
+    private ImageView mShorter;
+    private ImageView mLonger;
+    private SeekBar mSeekBar;
+    private ToggleAutoclickCustomSeekbarController mController;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        final String mPrefKey = "prefKey";
+        mContext = ApplicationProvider.getApplicationContext();
+        mSharedPreferences = mContext.getSharedPreferences(mContext.getPackageName(), MODE_PRIVATE);
+        mDelayLabel = new TextView(mContext);
+        mShorter = new ImageView(mContext);
+        mLonger = new ImageView(mContext);
+        mSeekBar = new SeekBar(mContext);
+        mController =
+                new ToggleAutoclickCustomSeekbarController(mContext, mLifecycle, mPrefKey);
+
+        doReturn(mLayoutPreference).when(mScreen).findPreference(mPrefKey);
+        doReturn(mSeekBar).when(mLayoutPreference).findViewById(R.id.autoclick_delay);
+        doReturn(mDelayLabel).when(mLayoutPreference).findViewById(R.id.current_label);
+        doReturn(mShorter).when(mLayoutPreference).findViewById(R.id.shorter);
+        doReturn(mLonger).when(mLayoutPreference).findViewById(R.id.longer);
+    }
+
+    @Test
+    public void getAvailabilityStatus_available() {
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void constructor_hasLifecycle_addObserver() {
+        verify(mLifecycle).addObserver(any(LifecycleObserver.class));
+    }
+
+    @Test
+    public void displayPreference_initSeekBar() {
+        mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, 700).apply();
+
+        mController.onResume();
+        mController.displayPreference(mScreen);
+        mController.onPause();
+        final SeekBar.OnSeekBarChangeListener mListener =
+                shadowOf(mSeekBar).getOnSeekBarChangeListener();
+
+        assertThat(mSeekBar.getMax()).isEqualTo(8);
+        assertThat(mSeekBar.getProgress()).isEqualTo(5);
+        assertThat(mListener).isNotNull();
+    }
+
+    @Test
+    public void displayPreference_initDelayLabel() {
+        mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, 700).apply();
+
+        mController.onResume();
+        mController.displayPreference(mScreen);
+        mController.onPause();
+
+        assertThat(mDelayLabel.getText()).isEqualTo("0.7 seconds");
+    }
+
+    @Test
+    public void onSharedPreferenceChanged_delayMode_updateCustomDelayValue() {
+        mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, 700).apply();
+
+        mController.displayPreference(mScreen);
+        mController.onSharedPreferenceChanged(mSharedPreferences, KEY_DELAY_MODE);
+        final int actualDelayValue =
+                Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, /* def= */ 0);
+        final int actualCustomDelayValue =
+                mSharedPreferences.getInt(KEY_CUSTOM_DELAY_VALUE, /* defValue= */ 0);
+
+        assertThat(mDelayLabel.getText()).isEqualTo("0.7 seconds");
+        assertThat(mSeekBar.getProgress()).isEqualTo(5);
+        assertThat(actualDelayValue).isEqualTo(700);
+        assertThat(actualCustomDelayValue).isEqualTo(700);
+    }
+
+    @Test
+    public void onSeekBarProgressChanged_updateCustomDelayValue() {
+        mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, 700).apply();
+
+        mController.displayPreference(mScreen);
+        mController.mSeekBarChangeListener.onProgressChanged(mock(SeekBar.class),
+                /* value= */ 8,
+                true);
+        final int actualDelayValue =
+                Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, /* def= */ 0);
+        final int actualCustomDelayValue =
+                mSharedPreferences.getInt(KEY_CUSTOM_DELAY_VALUE, /* defValue= */ 0);
+
+        assertThat(mDelayLabel.getText()).isEqualTo("1 second");
+        assertThat(mSeekBar.getProgress()).isEqualTo(8);
+        assertThat(actualDelayValue).isEqualTo(1000);
+        assertThat(actualCustomDelayValue).isEqualTo(1000);
+    }
+
+    @Test
+    public void onShorterClicked_updateCustomDelayValue() {
+        mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, 700).apply();
+
+        mController.displayPreference(mScreen);
+        mShorter.callOnClick();
+        final int actualDelayValue =
+                Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, /* def= */ 0);
+        final int actualCustomDelayValue =
+                mSharedPreferences.getInt(KEY_CUSTOM_DELAY_VALUE, /* defValue= */ 0);
+
+        assertThat(mSeekBar.getProgress()).isEqualTo(4);
+        assertThat(mDelayLabel.getText()).isEqualTo("0.6 seconds");
+        assertThat(actualDelayValue).isEqualTo(600);
+        assertThat(actualCustomDelayValue).isEqualTo(600);
+    }
+
+    @Test
+    public void onLongerClicked_updateCustomDelayValue() {
+        mSharedPreferences.edit().putInt(KEY_CUSTOM_DELAY_VALUE, 700).apply();
+
+        mController.displayPreference(mScreen);
+        mLonger.callOnClick();
+        final int actualDelayValue =
+                Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, /* def= */ 0);
+        final int actualCustomDelayValue =
+                mSharedPreferences.getInt(KEY_CUSTOM_DELAY_VALUE, /* defValue= */ 0);
+
+        assertThat(mSeekBar.getProgress()).isEqualTo(6);
+        assertThat(mDelayLabel.getText()).isEqualTo("0.8 seconds");
+        assertThat(actualDelayValue).isEqualTo(800);
+        assertThat(actualCustomDelayValue).isEqualTo(800);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
index 68848af..7248ff6 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
@@ -51,7 +51,7 @@
 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.media.MediaDevice;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -219,13 +219,13 @@
         Intent intent = intentList.get(0);
 
         assertThat(TextUtils.equals(TEST_PACKAGE_NAME, intent.getStringExtra(
-                MediaOutputSliceConstants.EXTRA_PACKAGE_NAME))).isTrue();
-        assertThat(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG).isEqualTo(
+                MediaOutputConstants.EXTRA_PACKAGE_NAME))).isTrue();
+        assertThat(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG).isEqualTo(
                 intent.getAction());
-        assertThat(TextUtils.equals(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME,
+        assertThat(TextUtils.equals(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME,
                 intent.getPackage())).isTrue();
         assertThat(mToken == intent.getExtras().getParcelable(
-                MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN)).isTrue();
+                MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN)).isTrue();
     }
 
     @Test
@@ -240,13 +240,13 @@
         Intent intent = intentList.get(0);
 
         assertThat(TextUtils.isEmpty(intent.getStringExtra(
-                MediaOutputSliceConstants.EXTRA_PACKAGE_NAME))).isTrue();
-        assertThat(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG).isEqualTo(
+                MediaOutputConstants.EXTRA_PACKAGE_NAME))).isTrue();
+        assertThat(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG).isEqualTo(
                 intent.getAction());
-        assertThat(TextUtils.equals(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME,
+        assertThat(TextUtils.equals(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME,
                 intent.getPackage())).isTrue();
         assertThat(intent.getExtras().getParcelable(
-                MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN) == null).isTrue();
+                MediaOutputConstants.KEY_MEDIA_SESSION_TOKEN) == null).isTrue();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
index eb84a4f..f604193 100644
--- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
@@ -58,7 +58,7 @@
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
-import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.settingslib.media.MediaOutputConstants;
 
 import org.junit.After;
 import org.junit.Before;
@@ -302,7 +302,7 @@
         mController.handlePreferenceTreeClick(mPreference);
         verify(mContext).sendBroadcast(intentCaptor.capture());
         assertThat(intentCaptor.getValue().getAction())
-                .isEqualTo(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG);
+                .isEqualTo(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG);
     }
 
     /**
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
deleted file mode 100644
index c7d0695..0000000
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.android.settings.wifi.tether;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.WifiManager;
-
-import androidx.preference.ListPreference;
-import androidx.preference.PreferenceScreen;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class WifiTetherSecurityPreferenceControllerTest {
-
-    private static final String WPA2_PSK =
-            String.valueOf(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
-    private static final String NONE = String.valueOf(SoftApConfiguration.SECURITY_TYPE_OPEN);
-    @Mock
-    private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
-    private Context mContext;
-    @Mock
-    private ConnectivityManager mConnectivityManager;
-    @Mock
-    private WifiManager mWifiManager;
-    @Mock
-    private PreferenceScreen mScreen;
-    private WifiTetherSecurityPreferenceController mController;
-    private ListPreference mPreference;
-    private SoftApConfiguration mConfig;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mConfig = new SoftApConfiguration.Builder().setSsid("test_1234")
-                .setPassphrase("test_password",
-                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK).build();
-        mContext = spy(RuntimeEnvironment.application);
-
-        when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
-        when(mWifiManager.getSoftApConfiguration()).thenReturn(mConfig);
-        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
-                .thenReturn(mConnectivityManager);
-        when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"1", "2"});
-        when(mScreen.findPreference(anyString())).thenReturn(mPreference);
-
-        mController = new WifiTetherSecurityPreferenceController(mContext, mListener);
-        mPreference = new ListPreference(RuntimeEnvironment.application);
-        mController.mPreference = mPreference;
-    }
-
-    @Test
-    public void onPreferenceChange_securityValueUpdated() {
-        mController.onPreferenceChange(mPreference, WPA2_PSK);
-        assertThat(mController.getSecurityType()).isEqualTo(
-                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
-        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
-
-        mController.onPreferenceChange(mPreference, NONE);
-        assertThat(mController.getSecurityType()).isEqualTo(
-                SoftApConfiguration.SECURITY_TYPE_OPEN);
-        assertThat(mPreference.getSummary().toString()).isEqualTo("None");
-    }
-
-    @Test
-    public void updateDisplay_preferenceUpdated() {
-        // test defaulting to WPA2-Personal on new config
-        when(mWifiManager.getSoftApConfiguration()).thenReturn(null);
-        mController.updateDisplay();
-        assertThat(mController.getSecurityType()).isEqualTo(
-                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
-        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
-
-        // test open tether network
-        SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
-                .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN).build();
-        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
-        mController.updateDisplay();
-        assertThat(mController.getSecurityType()).isEqualTo(
-                SoftApConfiguration.SECURITY_TYPE_OPEN);
-        assertThat(mPreference.getSummary().toString()).isEqualTo("None");
-
-        // test WPA2-Personal tether network
-        SoftApConfiguration config2 = new SoftApConfiguration.Builder(mConfig)
-                .setPassphrase("test_password",
-                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK).build();
-        when(mWifiManager.getSoftApConfiguration()).thenReturn(config2);
-        mController.updateDisplay();
-        assertThat(mController.getSecurityType()).isEqualTo(
-                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
-        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
-    }
-}
diff --git a/tests/unit/src/com/android/settings/wifi/WifiUtilsTest.java b/tests/unit/src/com/android/settings/wifi/WifiUtilsTest.java
index 7a75443..1a5e852 100644
--- a/tests/unit/src/com/android/settings/wifi/WifiUtilsTest.java
+++ b/tests/unit/src/com/android/settings/wifi/WifiUtilsTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiConfiguration;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -46,12 +47,48 @@
     public void testPassword() {
         final String longPassword = "123456789012345678901234567890"
                 + "1234567890123456789012345678901234567890";
-        assertThat(WifiUtils.isHotspotWpa2PasswordValid("123")).isFalse();
-        assertThat(WifiUtils.isHotspotWpa2PasswordValid("12345678")).isTrue();
-        assertThat(WifiUtils.isHotspotWpa2PasswordValid("1234567890")).isTrue();
-        assertThat(WifiUtils.isHotspotWpa2PasswordValid(longPassword)).isFalse();
-        assertThat(WifiUtils.isHotspotWpa2PasswordValid("")).isFalse();
-        assertThat(WifiUtils.isHotspotWpa2PasswordValid("€¥£")).isFalse();
+        assertThat(WifiUtils.isHotspotPasswordValid("123",
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isFalse();
+        assertThat(WifiUtils.isHotspotPasswordValid("12345678",
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid("1234567890",
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid(longPassword,
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isFalse();
+        assertThat(WifiUtils.isHotspotPasswordValid("",
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isFalse();
+        assertThat(WifiUtils.isHotspotPasswordValid("€¥£",
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isFalse();
+
+        // The WPA3_SAE_TRANSITION password limitation should be same as WPA2_PSK
+        assertThat(WifiUtils.isHotspotPasswordValid("123",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isFalse();
+        assertThat(WifiUtils.isHotspotPasswordValid("12345678",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid("1234567890",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid(longPassword,
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isFalse();
+        assertThat(WifiUtils.isHotspotPasswordValid("",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isFalse();
+        assertThat(WifiUtils.isHotspotPasswordValid("€¥£",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isFalse();
+
+        // The WA3_SAE password is requested that length > 1 only.
+        assertThat(WifiUtils.isHotspotPasswordValid("",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isFalse();
+        assertThat(WifiUtils.isHotspotPasswordValid("1",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid("123",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid("12345678",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid("1234567890",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid(longPassword,
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+        assertThat(WifiUtils.isHotspotPasswordValid("€¥£",
+                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
new file mode 100644
index 0000000..c86e3e5
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.tether;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Looper;
+
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class WifiTetherSecurityPreferenceControllerTest {
+
+    private static final String PREF_KEY = "wifi_tether_security";
+    private static final String WPA3_SAE =
+            String.valueOf(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+    private static final String WPA3_SAE_TRANSITION =
+            String.valueOf(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+    private static final String WPA2_PSK =
+            String.valueOf(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+    private static final String NONE = String.valueOf(SoftApConfiguration.SECURITY_TYPE_OPEN);
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
+
+    private WifiTetherSecurityPreferenceController mController;
+    private ListPreference mPreference;
+    private SoftApConfiguration mConfig;
+
+    @Before
+    public void setUp() {
+        final Context context = spy(ApplicationProvider.getApplicationContext());
+        mConfig = new SoftApConfiguration.Builder().setSsid("test_1234")
+                .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN).build();
+        when(context.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(mConfig);
+
+        mController = new WifiTetherSecurityPreferenceController(context, mListener);
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        final PreferenceManager preferenceManager = new PreferenceManager(context);
+        final PreferenceScreen screen = preferenceManager.createPreferenceScreen(context);
+        mPreference = new ListPreference(context);
+        mPreference.setKey(PREF_KEY);
+        screen.addPreference(mPreference);
+        mController.displayPreference(screen);
+    }
+
+    @Test
+    public void onPreferenceChange_toWpa3Sae_shouldUpdateSecurityValue() {
+        mController.onPreferenceChange(mPreference, WPA3_SAE);
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA3-Personal");
+    }
+
+    @Test
+    public void onPreferenceChange_toWpa3SaeTransition_shouldUpdateSecurityValue() {
+        mController.onPreferenceChange(mPreference, WPA3_SAE_TRANSITION);
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2/WPA3-Personal");
+    }
+
+    @Test
+    public void onPreferenceChange_toWpa2Psk_shouldUpdateSecurityValue() {
+        mController.onPreferenceChange(mPreference, WPA2_PSK);
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
+    }
+
+    @Test
+    public void onPreferenceChange_toNone_shouldUpdateSecurityValue() {
+        mController.onPreferenceChange(mPreference, NONE);
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("None");
+    }
+
+    @Test
+    public void updateDisplay_toWpa3Sae_shouldUpdateSecurityValue() {
+        SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+                .setPassphrase("test_password",
+                        SoftApConfiguration.SECURITY_TYPE_WPA3_SAE).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+        mController.updateDisplay();
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA3-Personal");
+    }
+
+    @Test
+    public void updateDisplay_toWpa3SaeTransition_shouldUpdateSecurityValue() {
+        SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+                .setPassphrase("test_password",
+                        SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+        mController.updateDisplay();
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2/WPA3-Personal");
+    }
+
+    @Test
+    public void updateDisplay_toWpa2Psk_shouldUpdateSecurityValue() {
+        SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+                .setPassphrase("test_password",
+                        SoftApConfiguration.SECURITY_TYPE_WPA2_PSK).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+        mController.updateDisplay();
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
+    }
+
+    @Test
+    public void updateDisplay_toNone_shouldUpdateSecurityValue() {
+        SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+                .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+        mController.updateDisplay();
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("None");
+    }
+
+    @Test
+    public void updateDisplay_toWpa3SaeButNotSupportWpa3_shouldBeDefaultToWpa2() {
+        mController.mIsWpa3Supported = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+                .setPassphrase("test_password",
+                        SoftApConfiguration.SECURITY_TYPE_WPA3_SAE).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+        mController.updateDisplay();
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
+    }
+
+    @Test
+    public void updateDisplay_toWpa3SaeTransitionButNotSupportWpa3_shouldBeDefaultToWpa2() {
+        mController.mIsWpa3Supported = false;
+        SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+                .setPassphrase("test_password",
+                        SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION).build();
+        when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+        mController.updateDisplay();
+
+        assertThat(mController.getSecurityType())
+                .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+        assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
+    }
+}